Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

851 lines
24 KiB

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