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

Windows Kernel

Development Platform:

Visual C++

  1. //--------------------------------------------------------------------------
  2. // Manage the windows list, such that we can get the IDispatch for each of
  3. // the shell windows to be marshalled to different processes
  4. //---------------------------------------------------------------------------
  5. //---------------------------------------------------------------------------
  6. // Includes...
  7. #include "priv.h"
  8. #include "sccls.h"
  9. #include <shdguid.h>
  10. #include "winlist.h"
  11. #include "iedde.h"
  12. #define DM_WINLIST  0
  13. void IEInitializeClassFactoryObject(IUnknown* punkAuto);
  14. void IERevokeClassFactoryObject(void);
  15. class CShellWindowListCF : public IClassFactory
  16. {
  17.     // IUnKnown
  18.     public:
  19.     virtual STDMETHODIMP QueryInterface(REFIID,void **);
  20.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  21.     virtual STDMETHODIMP_(ULONG) Release(void);
  22.     // IClassFactory
  23.     virtual STDMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject);
  24.     virtual STDMETHODIMP LockServer(BOOL fLock);
  25.     // constructor
  26.     CShellWindowListCF();
  27.     BOOL Init(void);
  28. protected:
  29.     ~CShellWindowListCF();
  30.     // locals
  31.     LONG            _cRef;
  32.     IShellWindows    *_pswWinList;
  33. };
  34. DWORD g_dwWinListCFRegister = 0;
  35. DWORD g_fWinListRegistered = FALSE;     // Only used in browser only mode...
  36. IShellWindows *g_pswWinList = NULL;
  37. // Function to get called by the tray to create the global window list and register
  38. // it with the system
  39. //=================================== Class Factory implemention ========================
  40. CShellWindowListCF::CShellWindowListCF()
  41. {
  42.     _cRef = 1;
  43.     DllAddRef();
  44. }
  45. BOOL CShellWindowListCF::Init()
  46. {
  47.     HRESULT hres = CSDWindows_CreateInstance(&_pswWinList);
  48.     g_pswWinList = _pswWinList;
  49.     // First see if there already is one defined...
  50.     if (FAILED(hres))
  51.     {
  52.         TraceMsg(DM_WINLIST, "WinList_Init CoCreateInstance Failed: %x", hres);
  53.         return FALSE;
  54.     }
  55.     // And register our class factory with the system...
  56.     hres = CoRegisterClassObject(CLSID_ShellWindows, this,
  57.                                  CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER,
  58.                                  REGCLS_MULTIPLEUSE, &g_dwWinListCFRegister);
  59.     ASSERT(SUCCEEDED(hres));
  60.     //  this call governs when we will call CoRevoke on the CF
  61.     if (SUCCEEDED(hres) && g_pswWinList)
  62.         g_pswWinList->ProcessAttachDetach(TRUE);
  63.     // Create an instance of the underlying window list class...
  64.     TraceMsg(DM_WINLIST, "WinList_Init CoRegisterClass: %x", hres);
  65.     return SUCCEEDED(hres);
  66. }
  67. CShellWindowListCF::~CShellWindowListCF()
  68. {
  69.     if (_pswWinList)
  70.     {
  71.         g_pswWinList = NULL;
  72.         _pswWinList->Release();
  73.     }
  74.     DllRelease();
  75. }
  76. STDMETHODIMP CShellWindowListCF::QueryInterface(REFIID riid, void **ppvObj)
  77. {
  78.     static const QITAB qit[] = { 
  79.         QITABENT(CShellWindowListCF, IClassFactory), // IID_IClassFactory
  80.         { 0 }, 
  81.     };
  82.     return QISearch(this, qit, riid, ppvObj);
  83. }
  84. STDMETHODIMP_(ULONG) CShellWindowListCF::AddRef()
  85. {
  86.     return InterlockedIncrement(&_cRef);
  87. }
  88. STDMETHODIMP_(ULONG) CShellWindowListCF::Release()
  89. {
  90.     if (InterlockedDecrement(&_cRef))
  91.         return _cRef;
  92.     delete this;
  93.     return 0;
  94. }
  95. STDMETHODIMP CShellWindowListCF::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
  96. {
  97.     // aggregation checking is done in class factory
  98.     // For now simply use our QueryService to get the dispatch.
  99.     // this will do all of the things to create it and the like.
  100.     if (!_pswWinList) 
  101.     {
  102.         ASSERT(0);
  103.         return E_FAIL;
  104.     }
  105.     return _pswWinList->QueryInterface(riid, ppvObj);
  106. }
  107. STDMETHODIMP CShellWindowListCF::LockServer(BOOL fLock)
  108. {
  109.     return S_OK;    // we don't do anything with this...
  110. }
  111. // As this is marshalled over to the main shell process hopefully this will take care of
  112. // most of the serialization problems.  Probably still need a way to handle the case better
  113. // where a window is coming up at the same time the last one is going down...
  114. STDAPI CWinListShellProc_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  115. {
  116.     *ppunk = NULL;
  117.     if (g_dwWinListCFRegister)
  118.         return CO_E_OBJISREG;
  119.     CShellWindowListCF *pswWinList = new CShellWindowListCF;
  120.     if (pswWinList)
  121.     {
  122.         pswWinList->Init(); // tell it to initialize
  123.         *ppunk = SAFECAST(pswWinList, IUnknown *);
  124.         return NOERROR;
  125.     }
  126.     return E_OUTOFMEMORY;
  127. }
  128. BOOL WinList_Init(void)
  129. {
  130.     // Create our clas factory to register out there...
  131.     TraceMsg(DM_WINLIST, "WinList_Init called");
  132.     //
  133.     //  If this is not a browser-only install. Register the class factory
  134.     // object now with no instance. Otherwise, do it when the first instance
  135.     // is created (see shbrowse.cpp).
  136.     //
  137.     if (!g_fBrowserOnlyProcess)
  138.     {
  139.         //
  140.         //  First, register the class factory object for CLSID_InternetExplorer.
  141.         // Note that we pass NULL indicating that subsequent CreateInstance
  142.         // should simply create a new instance.
  143.         //
  144.         IEInitializeClassFactoryObject(NULL);
  145.         CShellWindowListCF *pswWinList = new CShellWindowListCF;
  146.         if (pswWinList)
  147.         {
  148.             BOOL fRetVal = pswWinList->Init(); // tell it to initialize
  149.             pswWinList->Release(); // Release our handle hopefully init registered
  150.             //
  151.             // Initialize IEDDE.
  152.             //
  153.             if (!IsBrowseNewProcessAndExplorer())
  154.                 IEDDE_Initialize();
  155.             return fRetVal;
  156.         }
  157.     }
  158.     else
  159.     {
  160.         //
  161.         // Initialize IEDDE. - Done before cocreate below for timing issues
  162.         //
  163.         IEDDE_Initialize();
  164.         // All of the main processing moved to first call to WinList_GetShellWindows
  165.         // as the creating of OLE object across processes screwed up DDE timing.
  166.         return TRUE;
  167.     }
  168.     return FALSE;
  169. }
  170. #ifdef UNIX
  171. HRESULT CoCreateShellWindows(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext,
  172.                  REFIID riid,  void **ppv)
  173. {
  174.     HRESULT hres;
  175.     if (!g_pswWinList)
  176.     {
  177.         hres = CSDWindows_CreateInstance(&g_pswWinList);
  178.         if (FAILED(hres))
  179.         {
  180.             return E_FAIL;
  181.         }
  182.     }
  183.     hres = g_pswWinList->QueryInterface(riid, ppv);
  184.     if (SUCCEEDED(hres))
  185.     {
  186.     g_dwWinListCFRegister = 1;
  187.     }
  188.     return hres;
  189. }
  190. #endif
  191. // Helper function to get the ShellWindows Object
  192. IShellWindows* WinList_GetShellWindows(BOOL fForceMarshalled)
  193. {
  194.     IShellWindows *psw;
  195.     if (fForceMarshalled)
  196.         psw = NULL;
  197.     else
  198.         psw = g_pswWinList;
  199.     if (psw) 
  200.     {
  201.         // Optimize the inter-thread case by using the global WinList,
  202.         // this makes opening folders much faster.
  203.         psw->AddRef();
  204.     } 
  205.     else 
  206.     {
  207.         SHCheckRegistry();
  208. #ifndef NO_RPCSS_ON_UNIX
  209.         HRESULT hres = CoCreateInstance(CLSID_ShellWindows, NULL,
  210.                          CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER,
  211.                          IID_IShellWindows,  (void **)&psw);
  212. #else
  213.         HRESULT hres = CoCreateShellWindows(CLSID_ShellWindows, NULL,
  214.                          CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER,
  215.                          IID_IShellWindows,  (void **)&psw);
  216. #endif
  217.         if ( (g_fBrowserOnlyProcess || !IsInternetExplorerApp()) && !g_fWinListRegistered)
  218.         {
  219.             // If it failed and we are not funning in integrated mode, and this is the
  220.             // first time for this process, we should then register the Window List with
  221.             // the shell process.  We moved that from WinList_Init as that caused us to
  222.             // do interprocess send/post messages to early which caused DDE to break...
  223.             g_fWinListRegistered = TRUE;    // only call once
  224.             if (FAILED(hres))
  225.             {
  226.                 SHLoadInProc(CLSID_WinListShellProc);
  227.                 hres = CoCreateInstance(CLSID_ShellWindows, NULL,
  228.                                  CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER,
  229.                                  IID_IShellWindows,  (void **)&psw);
  230.             }
  231.             if (psw)
  232.             {
  233.                 psw->ProcessAttachDetach(TRUE);
  234.             }
  235.         }
  236.         // hr == REGDB_E_CLASSNOTREG when the shell process isn't running.
  237.         // hr == RPC_E_CANTCALLOUT_ININPUTSYNCCALL happens durring DDE launch of IE.
  238.         // should investigate, but removing assert for IE5 ship.
  239.         AssertMsg(SUCCEEDED(hres) || hres == REGDB_E_CLASSNOTREG || hres == RPC_E_CANTCALLOUT_ININPUTSYNCCALL,
  240.                   TEXT("WinList_GetShellWindows CoCreateInst(CLSID_ShellWindows) failed %x"), hres);
  241.     }
  242.     return psw;
  243. }
  244. // Function to terminate our use of the window list.
  245. void WinList_Terminate(void)
  246. {
  247.     // Lets release everything in a thread safe way...
  248.     TraceMsg(DM_WINLIST, "WinList_Terminate called");
  249.     IEDDE_Uninitialize();
  250.     // Release our usage of the object to allow the system to clean it up
  251.     if (!g_fBrowserOnlyProcess)
  252.     {
  253.         //  this is the explorer process, and we control the vertical
  254.         if (g_dwWinListCFRegister) {
  255.             IShellWindows* psw = WinList_GetShellWindows(FALSE);
  256.             ASSERT(psw);
  257. #ifdef DEBUG
  258.             long cwindow = -1;
  259.             psw->get_Count(&cwindow);
  260.             //ASSERT(cwindow==0);
  261.             if (cwindow != 0)
  262.                 TraceMsg(DM_ERROR, "wl_t: cwindow=%d (!=0)", cwindow);
  263. #endif
  264.             psw->ProcessAttachDetach(FALSE);
  265.             psw->Release();
  266.             //  the processattachdetach() should kill the CF in our process
  267.             if (g_dwWinListCFRegister != 0)
  268.                 TraceMsg(DM_ERROR, "wl_t: g_dwWinListCFRegister=%d (!=0)", g_dwWinListCFRegister);
  269.         }
  270.         IERevokeClassFactoryObject();
  271.         CUrlHistory_CleanUp();
  272.     }
  273.     else
  274.     {
  275.         if (g_fWinListRegistered)
  276.         {
  277.             // only do this if we actually registered...
  278.             IShellWindows* psw = WinList_GetShellWindows(TRUE);
  279.             if (psw)
  280.             {
  281.                 psw->ProcessAttachDetach(FALSE);    // Tell it we are going away...
  282.                 psw->Release();
  283.             }
  284.         }
  285.     }
  286. #ifdef UNIX
  287.     if (g_pswWinList)
  288.     {
  289.         g_pswWinList->Release();
  290.     }
  291. #endif
  292. }
  293. //  BUGBUG chrisfra 10/17/96 - mike schmidt needs to look at why delayed
  294. //  register causes death in OleUnitialize accessing freed vtable
  295. //  in winlist, under ifdef, i've also made WinList_GetShellWindows ignore
  296. //  BOOLEAN parameter
  297. HRESULT WinList_Revoke(long dwRegister)
  298. {
  299. #ifndef DELAY_REGISTER
  300.     IShellWindows* psw = WinList_GetShellWindows(TRUE);
  301. #else
  302.     IShellWindows* psw = WinList_GetShellWindows(FALSE);
  303. #endif
  304.     HRESULT hres = E_FAIL;
  305.     TraceMsg(DM_WINLIST, "WinList_Reevoke called on %x", dwRegister);
  306.     ASSERT(psw);
  307.     if (psw)
  308.     {
  309.         hres = psw->Revoke((long)dwRegister);
  310.         ASSERT(SUCCEEDED(hres));
  311.         psw->Release();
  312.     }
  313.     return hres;
  314. }
  315. STDAPI NavigateToPIDL(IWebBrowser2* pwb, LPCITEMIDLIST pidl)
  316. {
  317.     HRESULT hr;
  318.     VARIANT varThePidl;
  319.     if (InitVariantFromIDList(&varThePidl, pidl))
  320.     {
  321.         hr = pwb->Navigate2(&varThePidl, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY);
  322.         VariantClear(&varThePidl);       // Needed to free the copy of the PIDL in varThePidl.
  323.     }
  324.     else
  325.         hr = E_OUTOFMEMORY;
  326.     return hr;
  327. }
  328. BOOL _InitVariantFromIDListLazy(IShellWindows* psw, VARIANT* pvar, LPCITEMIDLIST pidl)
  329. {
  330.     memset(pvar, 0, sizeof(*pvar));
  331.     ASSERT(pvar->vt == VT_EMPTY);
  332.     if (!pidl)
  333.         return TRUE;    // Leave as empty!
  334.     if (psw == g_pswWinList)
  335.     {
  336.         InitVariantFromIDListInProc(pvar, pidl);  // non-marshalled call
  337.         return TRUE;
  338.     }
  339.     return InitVariantFromIDList(pvar, pidl);
  340. }
  341. HRESULT WinList_NotifyNewLocation(IShellWindows* psw, long dwRegister, LPCITEMIDLIST pidl)
  342. {
  343.     HRESULT hres = E_UNEXPECTED;
  344.     if (pidl) {
  345.         VARIANT var;
  346.         if (_InitVariantFromIDListLazy(psw, &var, pidl)) {
  347.             hres = psw->OnNavigate(dwRegister, &var);
  348.             VariantClearLazy(&var);
  349.         } else {
  350.             hres = E_OUTOFMEMORY;
  351.         }
  352.     }
  353.     return hres;
  354. }
  355. // Winlist_RegisterPending
  356. STDAPI WinList_RegisterPending(DWORD dwThread, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlRoot, long *pdwRegister)
  357. {
  358.     // Register with the window list that we have a pidl that we are starting up.
  359.     HRESULT hres = E_UNEXPECTED;
  360.     ASSERT(!pidlRoot);
  361.     if (pidl)
  362.     {
  363.         IShellWindows* psw = WinList_GetShellWindows(FALSE);
  364.         if (psw)
  365.         {
  366.             VARIANT var;
  367.             if (_InitVariantFromIDListLazy(psw, &var, pidl))
  368.             {
  369.                 hres = psw->RegisterPending(dwThread, &var, PVAREMPTY, SWC_BROWSER, pdwRegister);
  370.             }
  371.             else
  372.             {
  373.                 hres = E_OUTOFMEMORY;
  374.             }
  375.             VariantClearLazy(&var);
  376.         }
  377.     }
  378.     return hres;
  379. }
  380. /*
  381.  * WinList_FindFolderWindow
  382.  *
  383.  * PERFORMANCE note - getting back the automation object (ppauto) is really
  384.  * expensive due to the marshalling overhead.  Don't query for it unless you
  385.  * absolutely need it!
  386.  */
  387. HRESULT WinList_FindFolderWindow(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlRoot, HWND *phwnd, IWebBrowserApp **ppauto)
  388. {
  389.     HRESULT hres = E_UNEXPECTED;
  390.     ASSERT(!pidlRoot);
  391.     if (ppauto)
  392.         *ppauto = NULL;
  393.     if (phwnd)
  394.         *phwnd = NULL;
  395.     if (pidl) 
  396.     {
  397.         // Try a cached psw if we don't need ppauto
  398.         IShellWindows* psw = WinList_GetShellWindows(ppauto != NULL);
  399.         if (psw)
  400.         {
  401.             VARIANT var;
  402.             if (_InitVariantFromIDListLazy(psw, &var, pidl)) 
  403.             {
  404.                 IDispatch* pdisp = NULL;
  405.                 hres = psw->FindWindow(&var, PVAREMPTY, SWC_BROWSER, (long *)phwnd,
  406.                         ppauto ? (SWFO_NEEDDISPATCH | SWFO_INCLUDEPENDING) : SWFO_INCLUDEPENDING,
  407.                         &pdisp);
  408.                 if (pdisp) 
  409.                 {
  410.                     // if this fails it's because we are inside SendMessage loop and ole doesn't like it
  411.                     if (ppauto)
  412.                         hres = pdisp->QueryInterface(IID_IWebBrowserApp, (void **)ppauto);
  413.                     pdisp->Release();
  414.                 }
  415.             }
  416.             VariantClearLazy(&var);
  417.             psw->Release();
  418.         }
  419.     }
  420.     return hres;
  421. }
  422. #if 0
  423. HRESULT WinList_OnActivate(IShellWindows* psw, long dwRegister, BOOL fActivate, LPCITEMIDLIST pidl)
  424. {
  425.     HRESULT hres;
  426.     hres = psw->OnActivated(dwRegister, fActivate);
  427.     if (!fActivate) {
  428.         hres = WinList_NotifyNewLocation(psw, dwRegister, pidl);
  429.     }
  430.     return hres;
  431. }
  432. #endif
  433. //===============================================================================
  434. // Support for Being able to open a folder and get it's idispatch...
  435. //
  436. class CGIDFWait
  437. {
  438. public:
  439.     ULONG AddRef(void) ;
  440.     ULONG Release(void);
  441.     BOOL Init(IShellWindows *psw, LPCITEMIDLIST pidl, DWORD dwPending);
  442.     void CleanUp(void);
  443.     HRESULT WaitForWindowToOpen(DWORD dwTimeout);
  444.     CGIDFWait(void);
  445.     protected:
  446.     ~CGIDFWait(void);
  447.         // internal class to watch for events...
  448.         class CGIDFEvents : public DShellWindowsEvents
  449.         {
  450.             public:
  451.             // IUnknown methods
  452.             //
  453.             virtual STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj);
  454.             virtual STDMETHODIMP_(ULONG) AddRef(void) ;
  455.             virtual STDMETHODIMP_(ULONG) Release(void);
  456.             // IDispatch methods
  457.             //
  458.             STDMETHOD(GetTypeInfoCount)(THIS_ UINT * pctinfo);
  459.             STDMETHOD(GetTypeInfo)(THIS_ UINT itinfo, LCID lcid, ITypeInfo * * pptinfo);
  460.             STDMETHOD(GetIDsOfNames)(THIS_ REFIID riid, OLECHAR * * rgszNames,
  461.                 UINT cNames, LCID lcid, DISPID * rgdispid);
  462.             STDMETHOD(Invoke)(THIS_ DISPID dispidMember, REFIID riid,
  463.                 LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult,
  464.                 EXCEPINFO * pexcepinfo, UINT * puArgErr);
  465.         } m_EventHandler;
  466.         friend class CGIDFEvents;
  467.         DWORD m_dwCookie;
  468.         IShellWindows *m_psw;
  469.         IConnectionPoint *m_picp;
  470.         DWORD m_dwPending;
  471.         LPITEMIDLIST m_pidl;
  472.         HANDLE m_hevent;
  473.         BOOL  m_fAdvised;
  474.         int m_cRef;
  475. };
  476. ULONG CGIDFWait::AddRef(void)
  477. {
  478.     m_cRef++;
  479.     return m_cRef;
  480. }
  481. ULONG CGIDFWait::Release(void)
  482. {
  483.     m_cRef--;
  484.     if (m_cRef != 0)
  485.         return m_cRef;
  486.     delete this;
  487.     return 0;
  488. }
  489. CGIDFWait::CGIDFWait(void)
  490. {
  491.     ASSERT(m_psw == NULL);
  492.     ASSERT(m_picp == NULL);
  493.     ASSERT(m_hevent == NULL);
  494.     ASSERT(m_dwCookie == 0);
  495.     ASSERT(m_fAdvised == FALSE);
  496.     m_cRef = 1;
  497.     return;
  498. }
  499. CGIDFWait::~CGIDFWait(void)
  500. {
  501.     ATOMICRELEASE(m_psw);
  502.     CleanUp();
  503.     if (m_hevent)
  504.         CloseHandle(m_hevent);
  505.     if (m_pidl)
  506.         ILFree(m_pidl);
  507. }
  508. BOOL CGIDFWait::Init(IShellWindows *psw, LPCITEMIDLIST pidl, DWORD dwPending)
  509. {
  510.     // First try to create an event object
  511.     m_hevent = CreateEvent(NULL, TRUE, FALSE, NULL);
  512.     if (!m_hevent)
  513.         return FALSE;
  514.     // We do not have a window or it is pending...
  515.     // first lets setup that we want to be notified of new windows.
  516.     if (FAILED(ConnectToConnectionPoint(SAFECAST(&m_EventHandler, IDispatch*), DIID_DShellWindowsEvents, TRUE, psw, &m_dwCookie, &m_picp)))
  517.         return FALSE;
  518.     // Save away passed in stuff that we care about.
  519.     m_psw = psw;
  520.     psw->AddRef();
  521.     m_pidl = ILClone(pidl);
  522.     m_dwPending = dwPending;
  523.     return TRUE;
  524. }
  525. void CGIDFWait::CleanUp(void)
  526. {
  527.     // Don't need to listen anmore.
  528.     if (m_dwCookie)
  529.     {
  530.         m_picp->Unadvise(m_dwCookie);
  531.         m_dwCookie = 0;
  532.     }
  533.     ATOMICRELEASE(m_picp);
  534. }
  535. HRESULT CGIDFWait::WaitForWindowToOpen(DWORD dwTimeOut)
  536. {
  537.     if (!m_hevent || !m_dwCookie)
  538.         return E_FAIL;
  539.     ENTERCRITICAL;
  540.     if (!m_fAdvised)
  541.         ResetEvent(m_hevent);
  542.     LEAVECRITICAL;
  543.     DWORD dwStart = GetTickCount();
  544.     DWORD dwWait = dwTimeOut;
  545.     DWORD dwWaitResult;
  546.     do
  547.     {
  548.         dwWaitResult= MsgWaitForMultipleObjects(1, &m_hevent,
  549.                                                 FALSE, // fWaitAll, wait for any one
  550.                                                 dwWait, QS_ALLINPUT);
  551.         // Check if we are signaled for a send message.
  552.         if (dwWaitResult != WAIT_OBJECT_0 + 1)
  553.         {
  554.             // No. Break out of the loop.
  555.             break;
  556.         }
  557.         // We may need to dispatch stuff here.
  558.         MSG msg;
  559.         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  560.         {
  561.             TranslateMessage(&msg);
  562.             DispatchMessage(&msg);
  563.         }
  564.         // than MSEC_MAXWAIT if we wait more than that.
  565.         //
  566.         dwWait = dwStart+dwTimeOut - GetTickCount();
  567.     } while (dwWait <= dwTimeOut);
  568.     BOOL fAdvised;
  569.     
  570.     {
  571.     ENTERCRITICAL;
  572.     
  573.     fAdvised = m_fAdvised;
  574.     m_fAdvised = FALSE;
  575.     
  576.     LEAVECRITICAL;
  577.     }
  578.     return fAdvised ? NOERROR : E_FAIL;
  579. }
  580. STDMETHODIMP CGIDFWait::CGIDFEvents::QueryInterface(REFIID riid, void **ppvOut)
  581. {
  582.     if (IsEqualIID(riid, IID_IDispatch) ||
  583.         IsEqualIID(riid, IID_IUnknown))
  584.     {
  585.         *ppvOut = SAFECAST(this, IDispatch *);
  586.     }
  587.     else if (IsEqualIID(riid, DIID_DShellWindowsEvents))
  588.     {
  589.         *ppvOut = SAFECAST(this, DShellWindowsEvents *);
  590.     }
  591.     else
  592.     {
  593.         *ppvOut = NULL;
  594.         return E_NOINTERFACE;
  595.     }
  596.     AddRef();
  597.     return S_OK;
  598. }
  599. ULONG CGIDFWait::CGIDFEvents::AddRef(void)
  600. {
  601.     CGIDFWait* pdfwait = IToClass(CGIDFWait, m_EventHandler, this);
  602.     return pdfwait->AddRef();
  603. }
  604. ULONG CGIDFWait::CGIDFEvents::Release(void)
  605. {
  606.     CGIDFWait* pdfwait = IToClass(CGIDFWait, m_EventHandler, this);
  607.     return pdfwait->Release();
  608. }
  609. HRESULT CGIDFWait::CGIDFEvents::GetTypeInfoCount(UINT *pctinfo)
  610. {
  611.     return E_NOTIMPL;
  612. }
  613. HRESULT CGIDFWait::CGIDFEvents::GetTypeInfo(UINT itinfo, LCID lcid,
  614.                                              ITypeInfo **pptinfo)
  615. {
  616.     return E_NOTIMPL;
  617. }
  618. HRESULT CGIDFWait::CGIDFEvents::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames,
  619.                                               UINT cNames, LCID lcid, DISPID *rgdispid)
  620. {
  621.     return E_NOTIMPL;
  622. }
  623. HRESULT CGIDFWait::CGIDFEvents::Invoke(DISPID dispid, REFIID riid,
  624.     LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult,
  625.     EXCEPINFO * pexcepinfo, UINT * puArgErr)
  626. {
  627.     CGIDFWait* pdfwait = IToClass(CGIDFWait, m_EventHandler, this);
  628.     if (dispid == DISPID_WINDOWREGISTERED)
  629.     {
  630.         ENTERCRITICAL;
  631.         
  632.         // Signal the event
  633.         pdfwait->m_fAdvised = TRUE;
  634.         ::SetEvent(pdfwait->m_hevent);
  635.         
  636.         LEAVECRITICAL;
  637.     }
  638.     return S_OK;
  639. }
  640. // BugBug:: this assumes not rooted
  641. STDAPI SHGetIDispatchForFolder(LPCITEMIDLIST pidl, IWebBrowserApp **ppauto)
  642. {
  643.     HRESULT hres = E_UNEXPECTED;
  644.     if (ppauto)
  645.         *ppauto = NULL;
  646.     if (!pidl)
  647.         return E_POINTER;
  648.     // Try a cached psw if we don't need ppauto
  649.     IShellWindows* psw = WinList_GetShellWindows(ppauto != NULL);
  650.     if (psw)
  651.     {
  652.         VARIANT var;
  653.         LONG lhwnd;
  654.         if (InitVariantFromIDList(&var, pidl)) 
  655.         {
  656.             IDispatch* pdisp;
  657.             hres = psw->FindWindow(&var, PVAREMPTY, SWC_BROWSER, &lhwnd,
  658.                     ppauto ? (SWFO_NEEDDISPATCH | SWFO_INCLUDEPENDING) : SWFO_INCLUDEPENDING,
  659.                     &pdisp);
  660.             if ((hres == E_PENDING) || (hres == S_FALSE))
  661.             {
  662.                 HRESULT hresOld = hres;
  663.                 hres = E_FAIL;
  664.                 CGIDFWait *pdfwait = new CGIDFWait();   // Setup a wait object...
  665.                 if (pdfwait)
  666.                 {
  667.                     if (pdfwait->Init(psw, pidl, 0))
  668.                     {
  669.                         if (hresOld == S_FALSE)
  670.                         {
  671.                             // Startup opening a new window
  672.                             SHELLEXECUTEINFO sei = {sizeof(SHELLEXECUTEINFO)};
  673.                             sei.lpIDList = (void *)pidl;
  674.                             //
  675.                             //  WARNING - old versions of ShellExec() didnt pay attention - ZekeL - 30-DEC-98
  676.                             //  to whether the hwnd is in the same process or not, 
  677.                             //  and so could fault in TryDDEShortcut().
  678.                             //  only pass the hwnd if the shell window shares 
  679.                             //  the same process.
  680.                             //
  681.                             sei.hwnd = GetShellWindow();
  682.                             DWORD idProcess;
  683.                             GetWindowThreadProcessId(sei.hwnd, &idProcess);
  684.                             if (idProcess != GetCurrentProcessId())
  685.                                 sei.hwnd = NULL;
  686.                             // Everything should have been initialize to NULL(0)
  687.                             sei.fMask = SEE_MASK_IDLIST | SEE_MASK_FLAG_DDEWAIT;
  688.                             sei.nShow = SW_SHOWNORMAL;
  689.                             hres = ShellExecuteEx(&sei) ? NOERROR : S_FALSE;
  690.                         }
  691.                         while ((hres = psw->FindWindow(&var, PVAREMPTY, SWC_BROWSER, &lhwnd,
  692.                                 ppauto ? (SWFO_NEEDDISPATCH | SWFO_INCLUDEPENDING) : SWFO_INCLUDEPENDING,
  693.                                 &pdisp)) != S_OK)
  694.                         {
  695.                             if (FAILED(pdfwait->WaitForWindowToOpen(20 * 1000)))
  696.                             {
  697.                                 hres = E_ABORT;
  698.                                 break;
  699.                             }
  700.                         }
  701.                     }
  702.                     pdfwait->CleanUp();   // No need to watch things any more...
  703.                     pdfwait->Release(); // release our use of this object...
  704.                 }
  705.             }
  706.             if (hres == S_OK && ppauto) 
  707.             {
  708.                 // if this fails this is because we are inside SendMessage loop
  709.                 hres = pdisp->QueryInterface(IID_IWebBrowserApp, (void **)ppauto);
  710.             }
  711.             if (pdisp)
  712.                 pdisp->Release();
  713.             VariantClear(&var);
  714.         }
  715.         psw->Release();
  716.     }
  717.     return hres;
  718. }
  719. #ifdef POSTPOSTSPLIT
  720. // at this point, this code should be loaded from browseui.dll
  721. #else
  722. #undef VariantCopy
  723. WINOLEAUTAPI VariantCopyLazy(VARIANTARG * pvargDest, VARIANTARG * pvargSrc)
  724. {
  725.     VariantClearLazy(pvargDest);
  726.     switch(pvargSrc->vt) {
  727.     case VT_I4:
  728.     case VT_UI4:
  729.     case VT_BOOL:
  730.         // we can add more
  731.         *pvargDest = *pvargSrc;
  732.         return S_OK;
  733.     case VT_UNKNOWN:
  734.         if (pvargDest) {
  735.             *pvargDest = *pvargSrc;
  736.             pvargDest->punkVal->AddRef();
  737.             return S_OK;
  738.         }
  739.         ASSERT(0);
  740.         return E_INVALIDARG;
  741.     }
  742.     return VariantCopy(pvargDest, pvargSrc);
  743. }
  744. //
  745. // WARNING: This function must be placed at the end because we #undef
  746. // VariantClear
  747. //
  748. #undef VariantClear
  749. HRESULT VariantClearLazy(VARIANTARG *pvarg)
  750. {
  751.     switch(pvarg->vt) 
  752.     {
  753.         case VT_I4:
  754.         case VT_UI4:
  755.         case VT_EMPTY:
  756.         case VT_BOOL:
  757.             // No operation
  758.             break;
  759.         case VT_UNKNOWN:
  760.             if(V_UNKNOWN(pvarg) != NULL)
  761.               V_UNKNOWN(pvarg)->Release();
  762.             break;
  763.         case VT_DISPATCH:
  764.             if(V_DISPATCH(pvarg) != NULL)
  765.               V_DISPATCH(pvarg)->Release();
  766.             break;
  767.         case VT_SAFEARRAY:
  768.             THR(SafeArrayDestroy(V_ARRAY(pvarg)));
  769.             break;
  770.         default:
  771.             return VariantClear(pvarg);
  772.     }
  773.     V_VT(pvarg) = VT_EMPTY;
  774.     return S_OK;
  775. }
  776. #endif