ratings.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 17k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #ifdef FEATURE_PICS
  3. #include "asyncrat.h"
  4. #include <ratings.h>
  5. #include "dochost.h"
  6. #include <mshtmdid.h>
  7. /* There is a PicsQuery structure in the following global array for each
  8.  * outstanding query.  It records the address of the PicsData structure in
  9.  * the corresponding w3doc, the window handle corresponding to the Mwin,
  10.  * and a serial number.  This way, RatingObtainQueryCallback can tell if
  11.  * the page the query corresponds to still exists, before posting a message;
  12.  * and PicsDataMessageLoop can tell if the doc still exists when the message
  13.  * finally gets delivered.
  14.  *
  15.  * The array is dynamically allocated and is protected by the main HTML
  16.  * critical section.
  17.  */
  18. HDSA g_haQueries = NULL;
  19. DWORD g_dwPicsSerial = 1L;
  20. const UINT c_cQueryAllocSize = 8; /* should be plenty by default */
  21. UINT g_crefQueries = 0;
  22. /* AddPicsQuery - add an outstanding PICS query to the list, given a window
  23.  * handle to send a completion message to.  Returns the serial number of the
  24.  * query for later reference.
  25.  */
  26. DWORD _AddPicsQuery(HWND hwnd)
  27. {
  28.     ENTERCRITICAL;
  29.     
  30.     DWORD dwRet = 0;
  31.     
  32.     if (g_haQueries == NULL) {
  33.         g_haQueries = DSA_Create(sizeof(PicsQuery), c_cQueryAllocSize);
  34.     }
  35.     
  36.     if (g_haQueries != NULL) {
  37.         PicsQuery q;
  38.         
  39.         q.dwSerial = ::g_dwPicsSerial++;
  40.         q.hwnd = hwnd;
  41.         q.lpvRatingDetails = NULL;
  42.         
  43.         if (DSA_InsertItem(g_haQueries, DA_LAST, &q) >= 0)
  44.             dwRet = q.dwSerial;
  45.     }
  46.     
  47.     LEAVECRITICAL;
  48.     
  49.     return dwRet;
  50. }
  51. /* RemovePicsQuery - remove an outstanding query based on its serial number.
  52. */
  53. void _RemovePicsQuery(DWORD dwSerial)
  54. {
  55.     ENTERCRITICAL;
  56.     
  57.     if (g_haQueries != NULL) {
  58.         UINT cQueries = DSA_GetItemCount(g_haQueries);
  59.         PicsQuery *pq = NULL;
  60.         for (UINT i=0; i<cQueries; i++) {
  61.             pq = (PicsQuery *)DSA_GetItemPtr(g_haQueries, i);
  62.             if (pq != NULL && pq->dwSerial == dwSerial)
  63.                 break;
  64.         }
  65.         
  66.         if (pq != NULL) {
  67.             if (pq->lpvRatingDetails != NULL)
  68.                 ::RatingFreeDetails(pq->lpvRatingDetails);
  69.             DSA_DeleteItem(g_haQueries, i);
  70.         }
  71.     }
  72.     
  73.     LEAVECRITICAL;
  74. }
  75. /* GetPicsQuery - get a copy of an outstanding PICS query record, given its
  76.  * serial number.  Returns TRUE if found.
  77.  */
  78. BOOL _GetPicsQuery(DWORD dwSerial, PicsQuery *pOut)
  79. {
  80.     ENTERCRITICAL;
  81.     
  82.     PicsQuery *pq = NULL;
  83.     
  84.     if (g_haQueries != NULL) {
  85.         UINT cQueries = DSA_GetItemCount(g_haQueries);
  86.         for (UINT i=0; i<cQueries; i++) {
  87.             pq = (PicsQuery *)DSA_GetItemPtr(g_haQueries, i);
  88.             if (pq != NULL && pq->dwSerial == dwSerial)
  89.                 break;
  90.         }
  91.         
  92.         if (pq != NULL) {
  93.             *pOut = *pq;
  94.             pq->lpvRatingDetails = NULL; /* caller's copy owns this now */
  95.         }
  96.     }
  97.     
  98.     LEAVECRITICAL;
  99.     
  100.     return pq != NULL;
  101. }
  102. /* _RefPicsQueries - add a reference to the async query array */
  103. void _RefPicsQueries(void)
  104. {
  105.     ENTERCRITICAL;
  106.     ++g_crefQueries;
  107.     LEAVECRITICAL;
  108. }
  109. /* _ReleasePicsQueries - cleanup all memory associated with outstanding queries
  110.  */
  111. void _ReleasePicsQueries(void)
  112. {
  113.     ENTERCRITICAL;
  114.     
  115.     if (!--g_crefQueries) {
  116.         if (g_haQueries != NULL) {
  117.             UINT cQueries = DSA_GetItemCount(g_haQueries);
  118.             for (UINT i=0; i<cQueries; i++) {
  119.                 PicsQuery *pq = (PicsQuery *)DSA_GetItemPtr(g_haQueries, i);
  120.                 if (pq != NULL && pq->lpvRatingDetails != NULL) {
  121.                     RatingFreeDetails(pq->lpvRatingDetails);
  122.                 }
  123.             }
  124.             DSA_Destroy(g_haQueries);
  125.             g_haQueries = NULL;
  126.             // leave g_dwPicsSerial as it is, just in case we start up again
  127.         }
  128.     }
  129.     
  130.     LEAVECRITICAL;
  131. }
  132. /* PostPicsMessage - formats up a custom window message to signal that a
  133.  * query is complete.  Format is WM_PICS_STATUS(hresult,dwSerial).  Other
  134.  * information (the rating details blob obtained from RatingCheckUserAccess)
  135.  * is stored in the query record for safekeeping.
  136.  *
  137.  * Returns TRUE if a message was posted successfully to the right window.
  138.  */
  139. BOOL _PostPicsMessage(DWORD dwSerial, HRESULT hr, LPVOID lpvRatingDetails)
  140. {
  141.     BOOL fRet = FALSE;
  142.     
  143.     ENTERCRITICAL;
  144.     
  145.     if (g_haQueries != NULL) {
  146.         PicsQuery *pq = NULL;
  147.         UINT cQueries = DSA_GetItemCount(g_haQueries);
  148.         for (UINT i=0; i<cQueries; i++) {
  149.             pq = (PicsQuery *)DSA_GetItemPtr(g_haQueries, i);
  150.             if (pq != NULL && pq->dwSerial == dwSerial)
  151.                 break;
  152.         }
  153.         
  154.         if (pq != NULL) {
  155.             pq->lpvRatingDetails = lpvRatingDetails;
  156.             fRet = PostMessage(pq->hwnd, WM_PICS_ASYNCCOMPLETE, (WPARAM)hr,
  157.                 (LPARAM)dwSerial);
  158.             if (!fRet) { /* oops, couldn't post message, don't keep copy of details */
  159.                 pq->lpvRatingDetails = NULL;
  160.             }
  161.         }
  162.     }
  163.     
  164.     LEAVECRITICAL;
  165.     
  166.     return fRet;
  167. }
  168. /* Class CPicsRootDownload manages the download of the root document of a
  169.  * site, to get ratings from it.
  170.  */
  171. CPicsRootDownload::CPicsRootDownload(CDocObjectHost *pdoh, IOleCommandTarget *pctParent, BOOL fFrameIsOffline, BOOL fFrameIsSilent)
  172. {
  173.     m_cRef = 1;
  174.     m_pctParent = pctParent; m_pctParent->AddRef();
  175.     m_pdoh = pdoh; m_pdoh->AddRef();
  176.     m_pole = NULL;
  177.     m_pctObject = NULL;
  178.     m_pBinding = NULL;
  179.     m_fFrameIsOffline = fFrameIsOffline ? TRUE : FALSE;
  180.     m_fFrameIsSilent = fFrameIsSilent ? TRUE : FALSE;
  181. }
  182. CPicsRootDownload::~CPicsRootDownload()
  183. {
  184.     ATOMICRELEASE(m_pctParent);
  185.     CleanUp();
  186.     ATOMICRELEASE(m_pBinding);
  187.     ATOMICRELEASE(m_pBindCtx);
  188.     ATOMICRELEASET(m_pdoh,CDocObjectHost);
  189. }
  190. HRESULT CPicsRootDownload::StartDownload(IMoniker *pmk)
  191. {
  192.     IUnknown *punk = NULL;
  193.     HRESULT hr;
  194.     hr = CreateBindCtx(0, &m_pBindCtx);
  195.     if (FAILED(hr))
  196.         goto LErrExit;
  197.     /*
  198.     hr = m_pBindCtx->RegisterObjectParam(BROWSER_OPTIONS_OBJECT_NAME,
  199.                     (IBrowseControl *)this);
  200.     if (FAILED(hr))
  201.         goto LErrExit;
  202.     */
  203.     //
  204.     //  Associate the client site as an object parameter to this
  205.     // bind context so that Trident can pick it up while processing
  206.     // IPersistMoniker::Load().
  207.     //
  208.     m_pBindCtx->RegisterObjectParam(WSZGUID_OPID_DocObjClientSite,
  209.                                     SAFECAST(this, IOleClientSite*));
  210.     hr = RegisterBindStatusCallback(m_pBindCtx,
  211.             (IBindStatusCallback *)this,
  212.             0,
  213.             0L);
  214.     if (FAILED(hr))
  215.         goto LErrExit;
  216.     hr = pmk->BindToObject(m_pBindCtx, NULL, IID_IUnknown, (LPVOID*)&punk);
  217.     if (SUCCEEDED(hr) || hr==E_PENDING)
  218.     {
  219.         hr = S_OK;
  220.         //
  221.         // If moniker happen to return the object synchronously, emulate
  222.         // OnDataAvailable callback and OnStopBinding.
  223.         //
  224.         if (punk)
  225.         {
  226.             OnObjectAvailable(IID_IUnknown, punk);
  227.             OnStopBinding(hr, NULL);
  228.             punk->Release();
  229.         }
  230.     }
  231.     else
  232.     {
  233.         /* OnStopBinding can be called by URLMON within the BindToObject
  234.          * call in some cases.  So, don't call it ourselves if it's
  235.          * already been called (we can tell by looking whether our
  236.          * bind context still exists).
  237.          */
  238.         if (m_pBindCtx != NULL) {
  239.             OnStopBinding(hr, NULL);
  240.         }
  241.     }
  242. LErrExit:
  243.     if (FAILED(hr) && (m_pBindCtx != NULL)) {
  244.         m_pBindCtx->Release();
  245.         m_pBindCtx = NULL;
  246.     }
  247.     return hr;
  248. }
  249. /* _NotifyEndOfDocument is used in all the error cases to make sure the caller
  250.  * gets a notification of some sort.  The case where this function does not
  251.  * send a notification is if we have a valid OLE object -- in that case, we're
  252.  * assuming that we have it because we know it supports PICS, therefore we're
  253.  * expecting it to send such a notification to the parent itself.
  254.  */
  255. void CPicsRootDownload::_NotifyEndOfDocument(void)
  256. {
  257.     if (m_pole == NULL) {
  258.         if (m_pctParent != NULL) {
  259.             m_pctParent->Exec(&CGID_ShellDocView, SHDVID_NOMOREPICSLABELS, 0, NULL, NULL);
  260.         }
  261.     }
  262. }
  263. HRESULT CPicsRootDownload::_Abort()
  264. {
  265.     if (m_pBinding)
  266.     {
  267.         return m_pBinding->Abort();
  268.     }
  269.     return S_FALSE;
  270. }
  271. void CPicsRootDownload::CleanUp()
  272. {
  273.     _Abort();
  274.     if (m_pctObject != NULL) {
  275.         VARIANTARG v;
  276.         v.vt = VT_UNKNOWN;
  277.         v.lVal = (DWORD)0;
  278.         m_pctObject->Exec(&CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL);
  279.         m_pctObject->Exec(NULL, OLECMDID_STOP, NULL, NULL, NULL);
  280.         ATOMICRELEASE(m_pctObject);
  281.     }
  282.     LPOLECLIENTSITE pcs;
  283.     if (m_pole && SUCCEEDED(m_pole->GetClientSite(&pcs)) && pcs) 
  284.     {
  285.         if (pcs == SAFECAST(this, LPOLECLIENTSITE)) 
  286.         {
  287.             m_pole->SetClientSite(NULL);
  288.         }
  289.         pcs->Release();
  290.     }
  291.     ATOMICRELEASE(m_pole);
  292. }
  293. // IUnknown members
  294. STDMETHODIMP CPicsRootDownload::QueryInterface(REFIID riid, void **punk)
  295. {
  296.     *punk = NULL;
  297.     if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IsPicsBrowser))
  298.         *punk = (IUnknown *)(IBindStatusCallback *)this;
  299.     else if (IsEqualIID(riid, IID_IBindStatusCallback))
  300.         *punk = (IBindStatusCallback *)this;
  301.     else if (IsEqualIID(riid, IID_IOleClientSite))
  302.         *punk = (IOleClientSite *)this;
  303.     else if (IsEqualIID(riid, IID_IServiceProvider))
  304.         *punk = (IServiceProvider *)this;
  305.     else if (IsEqualIID(riid, IID_IDispatch))
  306.         *punk = (IDispatch *)this;
  307.     if (*punk != NULL) {
  308.         ((IUnknown *)(*punk))->AddRef();
  309.         return S_OK;
  310.     }
  311.     return E_NOINTERFACE;
  312. }
  313. STDMETHODIMP_(ULONG) CPicsRootDownload::AddRef(void)
  314. {
  315.     ++m_cRef;
  316.     TraceMsg(TF_SHDREF, "CPicsRootDownload(%x)::AddRef called, new m_cRef=%d", this, m_cRef);
  317.     return m_cRef;
  318. }
  319. STDMETHODIMP_(ULONG) CPicsRootDownload::Release(void)
  320. {
  321.     UINT crefNew = --m_cRef;
  322.     TraceMsg(TF_SHDREF, "CPicsRootDownload(%x)::Release called, new m_cRef=%d", this, m_cRef);
  323.     if (!crefNew)
  324.         delete this;
  325.     return crefNew;
  326. }
  327. // IBindStatusCallback methods
  328. STDMETHODIMP CPicsRootDownload::OnStartBinding(DWORD dwReserved, IBinding* pbinding)
  329. {
  330.     if (m_pBinding != NULL)
  331.         m_pBinding->Release();
  332.     m_pBinding = pbinding;
  333.     if (m_pBinding != NULL)
  334.         m_pBinding->AddRef();
  335.     return S_OK;
  336. }
  337. STDMETHODIMP CPicsRootDownload::GetPriority(LONG* pnPriority)
  338. {
  339.     return E_NOTIMPL;
  340. }
  341. STDMETHODIMP CPicsRootDownload::OnLowResource(DWORD dwReserved)
  342. {
  343.     return E_NOTIMPL;
  344. }
  345. STDMETHODIMP CPicsRootDownload::OnProgress(ULONG ulProgress, ULONG ulProgressMax,
  346.                                            ULONG ulStatusCode, LPCWSTR pwzStatusText)
  347. {
  348.     /* If the root document's data type is not HTML, don't try to get any
  349.      * ratings out of it, just abort.
  350.      */
  351.     if (ulStatusCode == BINDSTATUS_CLASSIDAVAILABLE) {
  352.         BOOL fContinueDownload = FALSE;
  353.         CLSID clsid;
  354.         // CLSIDFromString is prototyped wrong, non const first param
  355.         HRESULT hresT = CLSIDFromString((WCHAR *)pwzStatusText, &clsid);
  356.         if (SUCCEEDED(hresT)) {
  357.             LPWSTR pwzProgID = NULL;
  358.             hresT = ProgIDFromCLSID(clsid, &pwzProgID);
  359.             if (SUCCEEDED(hresT)) {
  360.                 if (StrCmp(pwzProgID, L"htmlfile") == 0)
  361.                 {
  362.                     fContinueDownload = TRUE;
  363.                 }
  364.                 OleFree(pwzProgID);
  365.             }
  366.         }
  367.         if (!fContinueDownload) {
  368.             _Abort();
  369.         }
  370.     }
  371.     return S_OK;
  372. }
  373. STDMETHODIMP CPicsRootDownload::OnStopBinding(HRESULT hrResult, LPCWSTR szError)
  374. {
  375.     /* Some of the cleanup we do in here (RevokeObjectParam is suspect?) could
  376.      * remove our last reference, causing the Releases at the end to fault.
  377.      * Guard against this with an AddRef/Release.  Dochost does this too.
  378.      *
  379.      * BUGBUG - if URLMON is calling back through this object, shouldn't he
  380.      * have a reference to us?  If so, where is it?
  381.      */
  382.     AddRef();
  383.     /* Notify the caller that we've got to the end of the document */
  384.     _NotifyEndOfDocument();
  385.     m_pBindCtx->RevokeObjectParam(WSZGUID_OPID_DocObjClientSite);
  386.     ::RevokeBindStatusCallback(m_pBindCtx, (IBindStatusCallback *)this);
  387.     ATOMICRELEASE(m_pBinding);
  388.     ATOMICRELEASE(m_pBindCtx);
  389.     /* Undo above AddRef(). */
  390.     Release();
  391.     return S_OK;
  392. }
  393. void SetBindfFlagsBasedOnAmbient(BOOL fAmbientOffline, DWORD *pgrfBindf);
  394. STDMETHODIMP CPicsRootDownload::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo)
  395. {
  396.     if ( !pgrfBINDF || !pbindInfo || !pbindInfo->cbSize )
  397.         return E_INVALIDARG;
  398.     *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
  399.     *pgrfBINDF |= BINDF_GETNEWESTVERSION;
  400.     if(m_fFrameIsSilent)
  401.     {
  402.         *pgrfBINDF |= BINDF_NO_UI;  
  403.     }
  404.     else
  405.     {
  406.         *pgrfBINDF &= ~BINDF_NO_UI;
  407.     }
  408.     SetBindfFlagsBasedOnAmbient(BOOLIFY(m_fFrameIsOffline), pgrfBINDF);
  409.     
  410.     // clear BINDINFO except cbSize
  411.     DWORD cbSize = pbindInfo->cbSize;
  412.     ZeroMemory( pbindInfo, cbSize );
  413.     pbindInfo->cbSize = cbSize;
  414.     pbindInfo->dwBindVerb = BINDVERB_GET;
  415.     return S_OK;
  416. }
  417. STDMETHODIMP CPicsRootDownload::OnDataAvailable(DWORD grfBSCF, DWORD dwSize,
  418.                                                 FORMATETC *pfmtetc,
  419.                                                 STGMEDIUM* pstgmed)
  420. {
  421.     return E_NOTIMPL;
  422. }
  423. STDMETHODIMP CPicsRootDownload::OnObjectAvailable(REFIID riid, IUnknown* punk)
  424. {
  425.     if (SUCCEEDED(punk->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&m_pctObject))) {
  426.         VARIANTARG v;
  427.         v.vt = VT_UNKNOWN;
  428.         v.punkVal = (IOleCommandTarget *)m_pctParent;
  429.         HRESULT hresT = m_pctObject->Exec(&CGID_ShellDocView, SHDVID_CANSUPPORTPICS, 0, &v, NULL);
  430.         if (hresT == S_OK) {
  431.             hresT = punk->QueryInterface(IID_IOleObject, (LPVOID *)&m_pole);
  432.             if (FAILED(hresT))
  433.                 m_pole = NULL;
  434.         }
  435.     }
  436.     if (m_pole == NULL) {
  437.         ATOMICRELEASE(m_pctObject);
  438.         _Abort();
  439.     }
  440.     return S_OK;
  441. }
  442. // IOleClientSite
  443. STDMETHODIMP CPicsRootDownload::SaveObject(void)
  444. {
  445.     return E_NOTIMPL;
  446. }
  447. STDMETHODIMP CPicsRootDownload::GetMoniker(DWORD, DWORD, IMoniker **)
  448. {
  449.     return E_NOTIMPL;
  450. }
  451. STDMETHODIMP CPicsRootDownload::GetContainer(IOleContainer **)
  452. {
  453.     return E_NOTIMPL;
  454. }
  455. STDMETHODIMP CPicsRootDownload::ShowObject(void)
  456. {
  457.     return E_NOTIMPL;
  458. }
  459. STDMETHODIMP CPicsRootDownload::OnShowWindow(BOOL fShow)
  460. {
  461.     return E_NOTIMPL;
  462. }
  463. STDMETHODIMP CPicsRootDownload::RequestNewObjectLayout(void)
  464. {
  465.     return E_NOTIMPL;
  466. }
  467. // IServiceProvider (must be QI'able from IOleClientSite)
  468. STDMETHODIMP CPicsRootDownload::QueryService(REFGUID guidService,
  469.                                     REFIID riid, void **ppvObj)
  470. {
  471.     if (IsEqualGUID(guidService, SID_STopLevelBrowser)) {
  472.         if (IsEqualIID(riid, IID_IsPicsBrowser))
  473.             return QueryInterface(riid, ppvObj);
  474.         return E_NOINTERFACE;
  475.     }
  476.     return E_FAIL;
  477. }
  478. // IDispatch
  479. HRESULT CPicsRootDownload::Invoke(DISPID dispidMember, REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pdispparams,
  480.                         VARIANT FAR* pVarResult,EXCEPINFO FAR* pexcepinfo,UINT FAR* puArgErr)
  481. {
  482.     if (!pVarResult)
  483.         return E_INVALIDARG;
  484.     if (wFlags == DISPATCH_PROPERTYGET)
  485.     {
  486.         switch (dispidMember)
  487.         {
  488.         case DISPID_AMBIENT_DLCONTROL :
  489.             // We support IDispatch so that Trident can ask us to control the
  490.             // download.  By specifying all the following flags, and by NOT
  491.             // specifying DLCTL_DLIMAGES, DLCTL_VIDEOS, or DLCTL_BGSOUNDS,
  492.             // we ensure we only download the HTML doc itself, and not a lot
  493.             // of associated things that aren't going to help us find a META
  494.             // tag.
  495.             pVarResult->vt = VT_I4;
  496.             pVarResult->lVal = DLCTL_SILENT | DLCTL_NO_SCRIPTS | 
  497.                                DLCTL_NO_JAVA | DLCTL_NO_RUNACTIVEXCTLS |
  498.                                DLCTL_NO_DLACTIVEXCTLS | DLCTL_NO_FRAMEDOWNLOAD |
  499.                                DLCTL_NO_CLIENTPULL;
  500.             break;
  501.         default:
  502.             return DISP_E_MEMBERNOTFOUND;
  503.         }
  504.         return S_OK;
  505.     }
  506.     return DISP_E_MEMBERNOTFOUND;
  507. }
  508. #endif  /* FEATURE_PICS */