Re: CR: Removal of persistent plugin data

Tad Yeager <[email protected]>
Newsgroups gmane.comp.multimedia.helix.devel
Message-ID <[email protected]>
Proposed new interface is now called IHXMediaPlatformCleaner and has three 
methods:

HRESULT RemoveAllPreferences(void)
HRESULT RemovePersistentPluginData(void)
HRESULT RemoveNamedPreference(const char* pszPreferenceRootName)

The MediaPlatform shouldn't have to be restarted. Generally, if plugin data 
is missing from preferences, Plugin2Handler will regenerate it.  The 
exception that necessitates the change we're reviewing: if VerifyChecksum_ 
fails in Plugin2Handler::ReadPluginInfoFast (or ReadPluginInfoSlow), 
PluginHandlerData\FileInfoX is regenerated but 
PluginHandlerData\PluginInfoX is not. This may seem like a bug, but it 
prevents loading hacked plugins.

MediaPlatform should be initialized before calling these methods. 
MediaPlatform can be compiled and created with different features, eg 
CreateMediaPlatformEx entrypoint and HX_FEATURE_FILEPREFS preprocessor 
definition.  Preferences can be overriden by the application, so we need 
the application to setup MediaPlatform before calling any of these three 
functions.

I've added checks and comments describing expected state.  I've reworked 
the interface and implementation to enable removal of a preference at an 
arbitrary level of the preference hierarchy, allowing an application to 
remove only the preferences or mount points that it cares about. I've put 
the code that removes all preferences into its own function so that the 
parent-child preference iteration would be more readable.  This duplicates 
a small amount of code.

Questions or comments?
Thanks,
Tad Yeager



At 08:55 AM 2/25/2009, Greg Wright wrote:
>Does the media platform need to be 'restarted' after prefs are deleted, or
>perhaps re-initialized? We should make sure we define what state the platform
>and engine are in after such a function is called as it can be called at
>any time. Perhaps just not allowing the call after some point, not sure.
>
>Personally, I really don't like adding numbers to interfaces as we
>have done historically. Sometimes there isn't a better choice, but
>in this case I think it might be better named with something that
>referes to the platforms persistent data. Then you could clone the
>other calls like Purge() and Reset() into this new interface. Perhaps
>calls for the PluginPath stuff as well. Might be useful to have an
>interface you could pass around that does that kind of stuff but
>doesn't have Close(), Init() or other types of calls.
>
>--greg.
>
>
>
>
>
>
>Tad Yeager wrote:
>>Resending because a portion of a reply wasn't transmitted and there has 
>>been only one response.
>>Synopsis: encapsulate the removal of persistent plugin data in the 
>>MediaPlatform.
>>Summary:
>>Applications and browser plugins attempt to kill registry keys prior to 
>>loading MediaPlatform/ObjectBroker so that plugin handler data will be 
>>regenerated when mount points are added.  This happens at installation 
>>time or if an application detects that plugins have changed locations.
>>The attached changes to MediaPlatform expose a method that deletes 
>>preferences using code factored out of MediaPlatform's Reset() 
>>function.  The location and format of the persistent plugin data can 
>>change. The attached changes move ownership from MediaPlatform's clients 
>>to MediaPlatform.
>>Branchs:
>>head, hxclient_3_1_0_atlas
>>Affected: MediaPlatform.
>>Risks: low.

_______________________________________________
Helix-client-dev mailing list
[email protected]
http://lists.helixcommunity.org/mailman/listinfo/helix-client-dev
medpltfm.txt (text/plain, 16.3 KB)
? Makefile
? client_medpltfm.sln
? client_medpltfm.vcproj
? client_medpltfm_hxmedpltfmdll.sln
? client_medpltfm_hxmedpltfmdll.vcproj
? client_medpltfm_hxmedpltfmlib.sln
? client_medpltfm_hxmedpltfmlib.vcproj
? dbg32
? debug
? pylinktmp-hxmedpltfm
? ribosome_logs
? test
? text
Index: chxmedpltfm.cpp
===================================================================
RCS file: /cvsroot/client/medpltfm/chxmedpltfm.cpp,v
retrieving revision 1.51.2.19
diff -u -2 -0 -r1.51.2.19 chxmedpltfm.cpp
--- chxmedpltfm.cpp	8 Nov 2008 17:25:36 -0000	1.51.2.19
+++ chxmedpltfm.cpp	4 Mar 2009 02:30:41 -0000
@@ -55,72 +55,76 @@
 #include "hxwintyp.h"
 #include "hxwin.h"
 #include "chxmedpltfm.h"
 #include "chxmedpltfmex.h"
 #include "chxmedpltfmsched.h"
 #include "hxoptsc.h"
 #include "hxobjbrokrids.h"
 
 #include "chxpckts.h"
 #include "pckunpck.h"
 #include "hxpref.h"
 #include "hxtbuf.h"
 #include "hxmutex.h"
 #include "timebuff.h"
 #include "hxcore.h"
 
 #include "hxvalues.h"
 #include "hxrquest.h"
 #include "hxfiles.h"
 #include "hxlistp.h"
+#include "hxstack.h"
+#include "hxstring.h"
+#include "hxpreferencesutils.h"
 #include "dllaccesserver.h"
 #include "cachobj.h"
 #include "chxfgbuf.h"
 #include "hxfsmgr.h"
 #include "hxgrpen2.h"
 #include "threngin.h"
 #include "hxclreg.h"
 #include "hxvsurf.h"
 #include "hxsite2.h"
 #include "hxmisus.h"
 #include "cpacemkr.h"
 #include "chxthread.h"
 #include "hxpreferences.h"
 #include "recognizer.h"
 #include "hxxml.h"
 #include "hxxmlprs.h"
 #ifdef HELIX_FEATURE_HTTP_SERVICE
 #include "chxhttp.h"
 #include "hxhttp.h"
 #endif
 #include "hxinfcod.h"
 #include "hxver.h"
 #include "hxstrutl.h"
 #include "dbcs.h"
 #include "thrdutil.h"
 
 #include "hxtlogutil.h"
 
 //------------------------------- CHXMediaPlatform
 
 BEGIN_INTERFACE_LIST( CHXMediaPlatform )
     INTERFACE_LIST_ENTRY_SIMPLE( IHXMediaPlatform ) 
+    INTERFACE_LIST_ENTRY_SIMPLE( IHXMediaPlatformCleaner ) 
     INTERFACE_LIST_ENTRY_SIMPLE( IHXCommonClassFactory ) 
     INTERFACE_LIST_ENTRY_SIMPLE( IHXObjectManagerPrivate )
     INTERFACE_LIST_ENTRY_DELEGATE_BLIND( _InternalQI )
 END_INTERFACE_LIST
 
 
 CHXMediaPlatform* CHXMediaPlatform::CreateInstance(CHXMediaPlatform* pParent, 
                                                    CHXMediaPlatform* pRoot)
 {
 #ifdef HELIX_FEATURE_EXTENDED_MEDIAPLATFORM
     return new CHXMediaPlatformEx((CHXMediaPlatformEx*)pParent, (CHXMediaPlatformEx*)pRoot);
 #else   // HELIX_FEATURE_EXTENDED_MEDIAPLATFORM
     return new CHXMediaPlatform(pParent, pRoot);
 #endif  // HELIX_FEATURE_EXTENDED_MEDIAPLATFORM
 }
 
 
 CHXMediaPlatform::CHXMediaPlatform(CHXMediaPlatform* pParent, CHXMediaPlatform* pRoot)
     :m_bInitialized(FALSE)
     ,m_lastError(HXR_OK)
@@ -586,44 +590,40 @@
     }
 
     // Extended context must be released last as it may have overriden 
     // services used by pther platform objects and it may also have 
     // aggregated itself into the platform.
     // In such case, releasing of the external context will result in its
     // destruction and thus any objects that may use its service must
     // be released/closed first.
     HX_RELEASE(m_pExtCCF);
     HX_RELEASE(m_pExtContext);
 
     m_bInitialized = FALSE;
 
     return HXR_OK;
 }
 
 STDMETHODIMP
 CHXMediaPlatform::Reset(IUnknown* pContext, HXBOOL bPlatformOnly)
 {
     HX_RESULT                   rc = HXR_OK;
-    IHXBuffer*                  pPrefKey = NULL;
-    IHXPreferences2*            pPref2 = NULL;
-    IHXPreferences3*            pPref3 = NULL;
-    IHXPreferenceEnumerator*    pPrefEnumerator = NULL;
     IHXPluginEnumerator*        pPluginEnumerator = NULL;
 
     if (!bPlatformOnly && m_pPluginHandlerUnkown)
     {
         if (HXR_OK == m_pPluginHandlerUnkown->QueryInterface(IID_IHXPluginEnumerator,
                                                              (void**)&pPluginEnumerator))
         {
             UINT32      ulIndex = 0;
             UINT32      ulNumOfPlugins = pPluginEnumerator->GetNumOfPlugins();
             IUnknown*   pPlugin = NULL;
             IHXPlugin2* pPlugin2 = NULL;
 
             for(ulIndex = 0; ulIndex < ulNumOfPlugins; ulIndex++)
             {
                 if (SUCCEEDED(pPluginEnumerator->GetPlugin(ulIndex, pPlugin)))
                 {
                     if (SUCCEEDED(pPlugin->QueryInterface(IID_IHXPlugin2, (void**)&pPlugin2)))
                     {
                         pPlugin2->Reset();
                     }
@@ -632,58 +632,217 @@
                 HX_RELEASE(pPlugin);
             }
         }
         HX_RELEASE(pPluginEnumerator);   
     }
 
     // We reset the m_pPreferences if it's already initialized via Init()
     //
     // On the other hand, Reset() can be called without Init(), this can
     // happen when the app simply wants to reset the media platform
     // during its un-installation
     if (!m_pPreferences)
     {       
         if (!m_pExtContext ||
             HXR_OK != m_pExtContext->QueryInterface(IID_IHXPreferences, (void**)&m_pPreferences))
         {
             InitDefaultPreferences();
         }
     }
 
-    // remove all the entries within m_pPreferences
-    if (m_pPreferences &&
-        HXR_OK == m_pPreferences->QueryInterface(IID_IHXPreferences2, (void**)&pPref2) &&
+    RemoveAllPreferences();
+
+    Close();
+
+    return HXR_OK;
+}
+
+void FlushPreferences(IHXPreferences* pPreferences)
+{
+#if defined(HELIX_FEATURE_FILEPREFS)
+    SPIHXPreferencesFile spFilePrefs = pPreferences;
+    if (spFilePrefs)
+    {
+        spFilePrefs->Flush();
+    }
+#endif // HELIX_FEATURE_FILEPREFS
+}
+
+STDMETHODIMP
+CHXMediaPlatform::RemoveAllPreferences(void)
+{
+    // Unlike Reset, we want the application to initialize preferences before 
+    // calling this function because preferences can be overridden by applications.  
+    if (!m_bInitialized || !m_pPreferences)
+    {
+        return HXR_NOT_INITIALIZED;
+    }
+
+    IHXBuffer*                  pPrefKey = NULL;
+    IHXPreferences2*            pPref2 = NULL;
+    IHXPreferences3*            pPref3 = NULL;
+    IHXPreferenceEnumerator*    pPrefEnumerator = NULL;
+    // Preferences must be initalized or we do nothing
+    if (HXR_OK == m_pPreferences->QueryInterface(IID_IHXPreferences2, (void**)&pPref2) &&
         HXR_OK == m_pPreferences->QueryInterface(IID_IHXPreferences3, (void**)&pPref3) &&
         HXR_OK == pPref2->GetPreferenceEnumerator(pPrefEnumerator))
     {
         while (HXR_OK == pPrefEnumerator->GetPrefKey(0, pPrefKey))
         {
             pPref3->DeletePref((const char*)pPrefKey->GetBuffer());
+        }
+    }
+
+    FlushPreferences(m_pPreferences);
+    return HXR_OK;
+}
+
+STDMETHODIMP
+CHXMediaPlatform::RemovePersistentPluginData(void)
+{
+    return RemovePreferences("MountPoints");
+}
+
+STDMETHODIMP
+CHXMediaPlatform::RemoveNamedPreference(const char* pszPreferenceRootName)
+{
+    return RemovePreferences(pszPreferenceRootName);
+}
+
+HX_RESULT         
+CHXMediaPlatform::RemovePreferences(const char* pszPreferenceRootName)
+{
+    // Unlike Reset, we want the application to initialize preferences before 
+    // calling this function because preferences can be overridden by applications.  
+    if (!m_bInitialized || !m_pPreferences)
+    {
+        return HXR_NOT_INITIALIZED;
+    }
+    HX_RESULT hr = RemovePreferences(m_pPreferences, pszPreferenceRootName);
+
+    FlushPreferences(m_pPreferences);
+    return hr;
+}
+
+bool FoundPreferenceKey(IHXBuffer* pPrefKey, const char* pszPreferenceRootName, int nPreferenceLength)
+{
+return ((int)pPrefKey->GetSize() >= nPreferenceLength && // assume pPrefKey buffer may not be NULL terminated, 
+// Buffer size can be greater than string size by an arbitrary amount, so this check doesn't tell us what we want to know:
+//      (int)pPrefKey->GetSize() <= nPreferenceLength && // but don't allow "MountPoints" to match "MountPointsWithSomeExtraStuff"
+        !strncmp(pszPreferenceRootName, (const char*)pPrefKey->GetBuffer(), nPreferenceLength)) ?
+        true : 
+        false;
+}
+
+void PushPreferenceName(CHXString* strCurrentPrefKey, IHXBuffer* pPrefKey)
+{
+    if (!strCurrentPrefKey->IsEmpty())
+    {
+        (*strCurrentPrefKey) += HXPreferencesUtils::czPrefKeySeparator;
+    }
+    (*strCurrentPrefKey) += (const char*)pPrefKey->GetBuffer();
+}
+
+void PopPreferenceName(CHXString* strCurrentPrefKey)
+{
+    INT32 nLastOccurence = strCurrentPrefKey->ReverseFind(HXPreferencesUtils::czPrefKeySeparator);
+    *strCurrentPrefKey = (nLastOccurence >= 0) ? strCurrentPrefKey->Left(nLastOccurence) : CHXString("");
+}
+
+HX_RESULT         
+CHXMediaPlatform::RemovePreferences(IHXPreferences* pPreferences, const char* pszPreferenceRootName)
+{
+    // Preferences must be initalized or we do nothing
+    if (!m_bInitialized || !pPreferences)
+    {
+        return HXR_NOT_INITIALIZED;
+    }
+
+    CHXStack                    preferenceIndicies;
+    CHXString                   strCurrentPrefKey;
+    IHXBuffer*                  pPrefKey = NULL;
+    IHXPreferences2*            pPref2 = NULL;
+    IHXPreferences3*            pPref3 = NULL;
+    IHXPreferenceEnumerator*    pPrefEnumerator = NULL;
+    int nPreferenceLength = 0;
+
+    // may be called with NULL preference root name, which means delete all preferences
+    if (pszPreferenceRootName)
+    {
+        nPreferenceLength = strlen(pszPreferenceRootName);
+    }
+
+    if (HXR_OK == pPreferences->QueryInterface(IID_IHXPreferences2, (void**)&pPref2) &&
+        HXR_OK == pPreferences->QueryInterface(IID_IHXPreferences3, (void**)&pPref3) &&
+        HXR_OK == pPref2->GetPreferenceEnumerator(pPrefEnumerator))
+    {
+        int i = 0;
+        bool bDone = (HXR_OK != pPrefEnumerator->GetPrefKey(i, pPrefKey));
+        while (!bDone)
+        {
+            // remove tree rooted at pszPreferenceRootName
+            if (FoundPreferenceKey(pPrefKey, pszPreferenceRootName, nPreferenceLength))
+            {
+                PushPreferenceName(&strCurrentPrefKey, pPrefKey);
+                pPref3->DeletePref(strCurrentPrefKey);
+                HX_RELEASE(pPrefKey);
+                // assuming only one preference name rooted as pszPreferenceRootName
+                // it's deleted, so we're done
+                break; 
+            }
+            else // descend into sub preferences
+            {
+                // Point parent index to next preference before pushing onto stack
+                i++;
+                // Begin sub pref; this will always succeed because pPrefKey is valid if
+                // we're here. GetPrefKey(0, ...) will fail below if there are no sub preferences
+                pPrefEnumerator->BeginSubPref((const char*)pPrefKey->GetBuffer());
+                preferenceIndicies.Push((void*)i);
+                PushPreferenceName(&strCurrentPrefKey, pPrefKey);
+                i = 0;
+            }
+            // Even if we're looking at SubPrefs, we're done with this pref because it didn't match
             HX_RELEASE(pPrefKey);
+
+            // Decide whether we need to pop subpref stack, continue or finish iteration
+            while (HXR_OK != pPrefEnumerator->GetPrefKey(i, pPrefKey))
+            {
+                // Enumerator is pointed past the last preference
+                if ((int)(void*)preferenceIndicies.TopOfStack() != 0)
+                {
+                    // Pop the subpref stack and continue iterating
+                    pPrefEnumerator->EndSubPref();
+                    i = (int)(void*)preferenceIndicies.Pop();
+                    PopPreferenceName(&strCurrentPrefKey);
+                }
+                else
+                {
+                    // Stack is empty, GetPrefKey failed, so we're done
+                    bDone = true;
+                    break;
+                }
+            }
         }
         HX_RELEASE(pPrefEnumerator);
         HX_RELEASE(pPref3);
         HX_RELEASE(pPref2);
     }
-
-    Close();
-
     return HXR_OK;
 }
 
 STDMETHODIMP
 CHXMediaPlatform::Purge(void)
 {
     // Purge is not supported on child media platform context
     if (m_pParent)
     {
         return m_pParent->Purge();
     }
 
 #if !defined(_STATICALLY_LINKED) && defined(HELIX_FEATURE_PLUGINHANDLER2)
     if (m_pPluginHandlerUnkown)
     {
         // shortcut, UnloadDeadDLLs() needs to be part of the interface 
         ((Plugin2Handler*)(IHXPlugin2Handler*)m_pPluginHandlerUnkown)->UnloadDeadDLLs();
     }
     
     return HXR_OK;
Index: pub/chxmedpltfm.h
===================================================================
RCS file: /cvsroot/client/medpltfm/pub/chxmedpltfm.h,v
retrieving revision 1.19.2.6
diff -u -2 -0 -r1.19.2.6 chxmedpltfm.h
--- pub/chxmedpltfm.h	6 Jun 2008 00:37:44 -0000	1.19.2.6
+++ pub/chxmedpltfm.h	4 Mar 2009 02:42:15 -0000
@@ -99,40 +99,41 @@
 struct PluginPathInfo
 {
     char*	pszName;
     IHXBuffer*	pPath;
 
     PluginPathInfo()
     {
 	pszName = NULL;
 	pPath = NULL;
     };
 
     ~PluginPathInfo()
     {
 	HX_VECTOR_DELETE(pszName);
 	HX_RELEASE(pPath);
     };
 };
 
 class CHXMediaPlatform : public CUnknownIMP
 		       , public IHXMediaPlatform
+		       , public IHXMediaPlatformCleaner
 		       , public IHXCommonClassFactory
 		       , public IHXObjectManagerPrivate
 {
     // The IUnknown implementation declaration
     DECLARE_UNKNOWN( CHXMediaPlatform )
 
 protected:
 
     typedef enum
     {
 	HX_MP_COM_INSTRINSIC = 0,
 	HX_MP_COM_REGULAR
     } HX_MP_COM_TYPE;
 
     HXBOOL		    m_bInitialized;
     HX_RESULT		    m_lastError;
 
     IUnknown*		    m_pExtContext;
     IUnknown*		    m_pPluginHandlerUnkown;
     IHXCommonClassFactory*  m_pExtCCF;
@@ -187,72 +188,84 @@
     CHXSimpleList*	    m_pSingleLoadPlugins;
     CHXSimpleList*          m_pLoadAtStartupPlugins;
 
     HX_RESULT		    InitBasicServices(void);
     HX_RESULT               LoadStartupPlugins(void);
     void                    UnloadStartupPlugins(void);
     HX_RESULT		    InitExtendableServices(void);
     HX_RESULT		    CheckAndQueryInterface(HX_MP_COM_TYPE type, REFIID riid, void** ppvObj);
     HX_RESULT		    CheckAndCreateInstance(HX_MP_COM_TYPE type, REFCLSID rclsid, void** ppUnknown);
 
     virtual HX_RESULT	    CreateIntrinsicType(REFCLSID rclsid, REF(IUnknown*) pUnknown, IUnknown* pOuter);
     virtual HX_RESULT	    CreateGeneralType(REFCLSID clsid, REF(IUnknown*) pObject, IUnknown* pUnkOuter, IUnknown* pContext);
 
     HX_RESULT		    CreateInstanceFromPluginHandler(REFCLSID rclsid, void** ppUnknown, IUnknown *pUnkOuter, IUnknown* pContext);
 
     HX_RESULT		    InitDefaultPreferences(void);
     HX_RESULT               InitLogging();
 
     HX_RESULT		    _InternalQI(REFIID riid, void** ppvObj);
 
+    // RemovePreferences is implemented in terms of the second RemovePreferences
+    HX_RESULT               RemovePreferences(const char* pszPreferenceRootName);
+    HX_RESULT               RemovePreferences(IHXPreferences* pPrefs, const char* pszPreferenceRootName);
 public:
     static CHXMediaPlatform* CreateInstance(CHXMediaPlatform* pParent = NULL, 
 					    CHXMediaPlatform* pRoot = NULL);
 
     CHXMediaPlatform(CHXMediaPlatform* pParent = NULL, CHXMediaPlatform* pRoot = NULL);
     ~CHXMediaPlatform(void);
 
     /*
      *  IHXMediaPlatform methods     
      *  see common/include/ihxmedpltfm.h for detail description
      */
     STDMETHOD(GetVersion)	(THIS_
 			         UINT32* pVersion);
 
     STDMETHOD(AddPluginPath)	(THIS_
 				 const char* pszName,
 				 const char* pszPath);
 
     STDMETHOD(Init)		(THIS_
 				 IUnknown* pContext);
 
     STDMETHOD(Close)		(THIS);
 
     STDMETHOD(Reset)		(THIS_
 				 IUnknown* pContext,
 				 HXBOOL	   bPlatformOnly = TRUE);
 
     STDMETHOD(Purge)		(THIS);
 
     STDMETHOD(CreateChildContext)   (THIS_
 				     IHXMediaPlatform** ppChildContext);
 
     /*
+     *	IHXMediaPlatformCleaner methods
+     */
+    STDMETHOD(RemovePersistentPluginData) (THIS);
+
+    STDMETHOD(RemoveNamedPreference) (THIS_ const char* pszPreferenceRootName);
+
+    STDMETHOD(RemoveAllPreferences) (THIS);
+
+    /*
      *	IHXCommonClassFactory methods
      */
     STDMETHOD(CreateInstance)		    (THIS_
 					     REFCLSID	rclsid,
 					     void**	ppUnknown);
 
     STDMETHOD(CreateInstanceAggregatable)   (THIS_
 					     REFCLSID	    rclsid,
 					     REF(IUnknown*) ppUnknown,
 					     IUnknown*	    pUnkOuter);
 
     // IHXObjectManagerPrivate methods
     STDMETHOD(ObjectFromCLSIDPrivate) (THIS_ REFCLSID clsid,REF(IUnknown *)pObject, 
 						IUnknown *pUnkOuter, IUnknown* pContext );
 
     STDMETHOD( UnloadPluginPrivate )(THIS_ REFCLSID clsid);
 };
 
 #endif /* _CHXMEDPLTFM_H_ */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.