Source code of Windows XP (NT5)
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.

408 lines
13 KiB

  1. #include "shellprv.h"
  2. #include "cowsite.h"
  3. #pragma hdrstop
  4. // this is the comdlg frame that we will use to host the file picker object, it mostly is
  5. // a stub that will forward accordingly
  6. //
  7. // the lifetime of this is handled by the DefView object we are attached to, which when
  8. // the parent (CFolderViewHost) is destroyed will be taken down.
  9. class CViewHostBrowser : public IShellBrowser, ICommDlgBrowser2, IServiceProvider
  10. {
  11. public:
  12. CViewHostBrowser(HWND hwndParent, IShellView *psvWeak, IUnknown *punkSiteWeak);
  13. ~CViewHostBrowser();
  14. // IServiceProvider
  15. STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv);
  16. // *** IUnknown methods ***
  17. STDMETHOD(QueryInterface)(REFIID riid, LPVOID *ppvObj);
  18. STDMETHOD_(ULONG,AddRef)(THIS);
  19. STDMETHOD_(ULONG,Release)(THIS);
  20. // *** IOleWindow methods ***
  21. STDMETHOD(GetWindow)(HWND *lphwnd)
  22. { *lphwnd = _hwndParent; return S_OK; }
  23. STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode)
  24. { return S_OK; }
  25. // *** IShellBrowser methods *** (same as IOleInPlaceFrame)
  26. STDMETHOD(InsertMenusSB)(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
  27. { return E_NOTIMPL; }
  28. STDMETHOD(SetMenuSB)(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
  29. { return S_OK; }
  30. STDMETHOD(RemoveMenusSB)(HMENU hmenuShared)
  31. { return E_NOTIMPL; }
  32. STDMETHOD(SetStatusTextSB)(LPCOLESTR lpszStatusText)
  33. { return S_OK; }
  34. STDMETHOD(EnableModelessSB)(BOOL fEnable)
  35. { return S_OK; }
  36. STDMETHOD(TranslateAcceleratorSB)(LPMSG lpmsg, WORD wID)
  37. { return S_FALSE; }
  38. // *** IShellBrowser methods ***
  39. STDMETHOD(BrowseObject)(LPCITEMIDLIST pidl, UINT wFlags)
  40. { return E_FAIL; }
  41. STDMETHOD(GetViewStateStream)(DWORD grfMode, LPSTREAM *pStrm)
  42. { return E_FAIL; }
  43. STDMETHOD(GetControlWindow)(UINT id, HWND *lphwnd)
  44. { return E_NOTIMPL; }
  45. STDMETHOD(SendControlMsg)(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret);
  46. STDMETHOD(QueryActiveShellView)(IShellView **ppshv);
  47. STDMETHOD(OnViewWindowActive)(IShellView *pshv)
  48. { return S_OK; }
  49. STDMETHOD(SetToolbarItems)(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
  50. { return S_OK; }
  51. // *** ICommDlgBrowser methods ***
  52. STDMETHOD(OnDefaultCommand)(IShellView *ppshv)
  53. { return S_OK; }
  54. STDMETHOD(OnStateChange)(IShellView *ppshv, ULONG uChange);
  55. STDMETHOD(IncludeObject)(IShellView *ppshv, LPCITEMIDLIST lpItem);
  56. // *** ICommDlgBrowser2 methods ***
  57. STDMETHOD(Notify)(IShellView *ppshv, DWORD dwNotifyType)
  58. { return S_FALSE; }
  59. STDMETHOD(GetDefaultMenuText)(IShellView *ppshv, WCHAR *pszText, INT cchMax)
  60. { return S_FALSE; }
  61. STDMETHOD(GetViewFlags)(DWORD *pdwFlags)
  62. { *pdwFlags = 0; return S_OK; }
  63. private:
  64. long _cRef;
  65. HWND _hwndParent;
  66. IShellView *_psvWeak;
  67. IUnknown *_punkSiteWeak; // not addref'd.
  68. friend class CFolderViewHost;
  69. };
  70. CViewHostBrowser::CViewHostBrowser(HWND hwndParent, IShellView *psvWeak, IUnknown *punkSiteWeak) :
  71. _cRef(1), _hwndParent(hwndParent), _psvWeak(psvWeak), _punkSiteWeak(punkSiteWeak)
  72. {
  73. // _psvWeak->AddRef(); // we hold a weak refernece to our parent, therefore don't AddRef()
  74. // _punkSiteWeak->AddRef(); // we hold a weak reference to our parent, therefore don't AddRef()!
  75. }
  76. CViewHostBrowser::~CViewHostBrowser()
  77. {
  78. // _psvWeak->Release(); // this is scoped on the lifetime of our parent
  79. // _punkSiteWeak->Release(); // we hold a weak reference to our parent, therefore don't Release()!
  80. }
  81. HRESULT CViewHostBrowser::QueryInterface(REFIID riid, void **ppvObj)
  82. {
  83. static const QITAB qit[] = {
  84. QITABENT(CViewHostBrowser, IShellBrowser), // IID_IShellBrowser
  85. QITABENT(CViewHostBrowser, ICommDlgBrowser2), // IID_ICommDlgBrowser2
  86. QITABENTMULTI(CViewHostBrowser, ICommDlgBrowser, ICommDlgBrowser2), // IID_ICommDlgBrowser
  87. QITABENT(CViewHostBrowser, IServiceProvider), // IID_IServiceProvider
  88. { 0 },
  89. };
  90. return QISearch(this, qit, riid, ppvObj);
  91. }
  92. ULONG CViewHostBrowser::AddRef()
  93. {
  94. return InterlockedIncrement(&_cRef);
  95. }
  96. ULONG CViewHostBrowser::Release()
  97. {
  98. if (InterlockedDecrement(&_cRef))
  99. return _cRef;
  100. delete this;
  101. return 0;
  102. }
  103. // IShellBrowser
  104. HRESULT CViewHostBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
  105. {
  106. if (pret)
  107. *pret = 0L;
  108. return S_OK;
  109. }
  110. HRESULT CViewHostBrowser::QueryActiveShellView(IShellView **ppshv)
  111. {
  112. HRESULT hr = E_NOINTERFACE;
  113. if (_psvWeak)
  114. {
  115. hr = _psvWeak->QueryInterface(IID_PPV_ARG(IShellView, ppshv));
  116. }
  117. return hr;
  118. }
  119. // ICommDlgBrowser - these are forwarded to our site object
  120. HRESULT CViewHostBrowser::OnStateChange(IShellView *ppshv, ULONG uChange)
  121. {
  122. HRESULT hr = S_OK;
  123. ICommDlgBrowser *pcdb;
  124. if (SUCCEEDED(IUnknown_QueryService(_punkSiteWeak, SID_SCommDlgBrowser, IID_PPV_ARG(ICommDlgBrowser, &pcdb))))
  125. {
  126. hr = pcdb->OnStateChange(ppshv, uChange);
  127. pcdb->Release();
  128. }
  129. return hr;
  130. }
  131. HRESULT CViewHostBrowser::IncludeObject(IShellView *ppshv, LPCITEMIDLIST lpItem)
  132. {
  133. HRESULT hr = S_OK;
  134. ICommDlgBrowser *pcdb;
  135. if (SUCCEEDED(IUnknown_QueryService(_punkSiteWeak, SID_SCommDlgBrowser, IID_PPV_ARG(ICommDlgBrowser, &pcdb))))
  136. {
  137. hr = pcdb->IncludeObject(ppshv, lpItem);
  138. pcdb->Release();
  139. }
  140. return hr;
  141. }
  142. // IServiceProvider
  143. HRESULT CViewHostBrowser::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
  144. {
  145. HRESULT hr = E_FAIL;
  146. *ppvObj = NULL;
  147. if (IsEqualGUID(guidService, SID_SCommDlgBrowser))
  148. {
  149. hr = this->QueryInterface(riid, ppvObj);
  150. }
  151. return hr;
  152. }
  153. // this is the file picker object it creates an IShellView (which for us should result in
  154. // a defview implement). from this we can then give the window to the caller and they
  155. // can place on their dialog as needed.
  156. class CFolderViewHost : public IFolderViewHost, IServiceProvider, IOleWindow, IFolderView, CObjectWithSite
  157. {
  158. public:
  159. CFolderViewHost();
  160. ~CFolderViewHost();
  161. // *** IFolderViewHost ***
  162. STDMETHODIMP Initialize(HWND hwndParent, IDataObject *pdo, RECT *prc);
  163. // *** IUnknown methods ***
  164. STDMETHOD(QueryInterface)(REFIID riid, LPVOID *ppvObj);
  165. STDMETHOD_(ULONG,AddRef)(THIS);
  166. STDMETHOD_(ULONG,Release)(THIS);
  167. // *** IOleWindow methods ***
  168. STDMETHOD(GetWindow)(HWND *lphwnd)
  169. { *lphwnd = _hwndView; return S_OK; }
  170. STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode)
  171. { return S_OK; }
  172. // IServiceProvider
  173. STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv)
  174. { return IUnknown_QueryService(_punkSite, guidService, riid, ppv); }
  175. // IFolderView
  176. STDMETHODIMP GetCurrentViewMode(UINT *pViewMode)
  177. { return _pfv->GetCurrentViewMode(pViewMode); }
  178. STDMETHODIMP SetCurrentViewMode(UINT ViewMode)
  179. { return _pfv->SetCurrentViewMode(ViewMode); }
  180. STDMETHODIMP GetFolder(REFIID ridd, void **ppv)
  181. { return _pfv->GetFolder(ridd, ppv); }
  182. STDMETHODIMP Item(int iItemIndex, LPITEMIDLIST *ppidl)
  183. { return _pfv->Item(iItemIndex, ppidl); }
  184. STDMETHODIMP ItemCount(UINT uFlags, int *pcItems)
  185. { return _pfv->ItemCount(uFlags, pcItems); }
  186. STDMETHODIMP Items(UINT uFlags, REFIID riid, void **ppv)
  187. { return _pfv->Items(uFlags, riid, ppv); }
  188. STDMETHODIMP GetSelectionMarkedItem(int *piItem)
  189. { return _pfv->GetSelectionMarkedItem(piItem); }
  190. STDMETHODIMP GetFocusedItem(int *piItem)
  191. { return _pfv->GetFocusedItem(piItem); }
  192. STDMETHODIMP GetItemPosition(LPCITEMIDLIST pidl, POINT* ppt)
  193. { return _pfv->GetItemPosition(pidl, ppt); }
  194. STDMETHODIMP GetSpacing(POINT* ppt)
  195. { return _pfv->GetSpacing(ppt); }
  196. STDMETHODIMP GetDefaultSpacing(POINT* ppt)
  197. { return _pfv->GetDefaultSpacing(ppt); }
  198. STDMETHODIMP GetAutoArrange()
  199. { return _pfv->GetAutoArrange(); }
  200. STDMETHODIMP SelectItem(int iItem, DWORD dwFlags)
  201. { return _pfv->SelectItem(iItem, dwFlags); }
  202. STDMETHODIMP SelectAndPositionItems(UINT cidl, LPCITEMIDLIST* apidl, POINT* apt, DWORD dwFlags)
  203. { return _pfv->SelectAndPositionItems(cidl, apidl, apt, dwFlags); }
  204. private:
  205. long _cRef;
  206. IFolderView *_pfv; // IFolderView
  207. HWND _hwndView;
  208. };
  209. CFolderViewHost::CFolderViewHost() :
  210. _cRef(1)
  211. {
  212. }
  213. CFolderViewHost::~CFolderViewHost()
  214. {
  215. if (_pfv)
  216. _pfv->Release();
  217. }
  218. HRESULT CFolderViewHost::QueryInterface(REFIID riid, void **ppvObj)
  219. {
  220. static const QITAB qit[] = {
  221. QITABENT(CFolderViewHost, IFolderViewHost), // IID_IFolderViewHost
  222. QITABENT(CFolderViewHost, IOleWindow), // IID_IOleWindow
  223. QITABENT(CFolderViewHost, IFolderView), // IID_IFolderView
  224. QITABENT(CFolderViewHost, IServiceProvider), // IID_IServiceProvider
  225. QITABENT(CFolderViewHost, IObjectWithSite), // IID_IObjectWithSite
  226. { 0 },
  227. };
  228. return QISearch(this, qit, riid, ppvObj);
  229. }
  230. ULONG CFolderViewHost::AddRef()
  231. {
  232. return InterlockedIncrement(&_cRef);
  233. }
  234. ULONG CFolderViewHost::Release()
  235. {
  236. if (InterlockedDecrement(&_cRef))
  237. return _cRef;
  238. delete this;
  239. return 0;
  240. }
  241. // the initialize method handles the creation of the view object from the.
  242. HRESULT CFolderViewHost::Initialize(HWND hwndParent, IDataObject *pdo, RECT *prc)
  243. {
  244. // first we perform a namespace walk, this will retrieve our selection from the view
  245. // using this we can then create the view object.
  246. INamespaceWalk *pnsw;
  247. HRESULT hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(INamespaceWalk, &pnsw));
  248. if (SUCCEEDED(hr))
  249. {
  250. LPITEMIDLIST *aItems = NULL;
  251. UINT cItems = 0;
  252. hr = pnsw->Walk(pdo, NSWF_NONE_IMPLIES_ALL, 0, NULL);
  253. if (SUCCEEDED(hr))
  254. {
  255. IShellFolder *psf = NULL;
  256. hr = pnsw->GetIDArrayResult(&cItems, &aItems);
  257. if (S_OK == hr)
  258. {
  259. hr = SHBindToIDListParent(aItems[0], IID_PPV_ARG(IShellFolder, &psf), NULL);
  260. }
  261. else if (S_FALSE == hr)
  262. {
  263. hr = E_FAIL; // fail unless we perform the bind.
  264. STGMEDIUM medium;
  265. LPIDA pida = DataObj_GetHIDA(pdo, &medium);
  266. if (pida)
  267. {
  268. if (pida->cidl == 1)
  269. {
  270. LPITEMIDLIST pidl = IDA_ILClone(pida, 0);
  271. if (pidl)
  272. {
  273. hr = SHBindToObjectEx(NULL, pidl, NULL, IID_PPV_ARG(IShellFolder, &psf));
  274. ILFree(pidl);
  275. }
  276. }
  277. HIDA_ReleaseStgMedium(pida, &medium);
  278. }
  279. }
  280. else
  281. {
  282. hr = E_FAIL;
  283. }
  284. if (SUCCEEDED(hr))
  285. {
  286. IShellView *psv;
  287. hr = psf->CreateViewObject(hwndParent, IID_PPV_ARG(IShellView, &psv));
  288. if (SUCCEEDED(hr))
  289. {
  290. CViewHostBrowser *pvhb = new CViewHostBrowser(hwndParent, psv, SAFECAST(this, IServiceProvider*));
  291. if (pvhb)
  292. {
  293. hr = psv->QueryInterface(IID_PPV_ARG(IFolderView, &_pfv));
  294. if (SUCCEEDED(hr))
  295. {
  296. FOLDERSETTINGS fs = {0};
  297. fs.ViewMode = FVM_THUMBNAIL;
  298. fs.fFlags = FWF_AUTOARRANGE|FWF_NOWEBVIEW|FWF_HIDEFILENAMES|FWF_CHECKSELECT;
  299. IFolderView *pfv;
  300. if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SFolderView, IID_PPV_ARG(IFolderView, &pfv))))
  301. {
  302. pfv->GetCurrentViewMode(&fs.ViewMode);
  303. pfv->Release();
  304. }
  305. hr = psv->CreateViewWindow(NULL, &fs, pvhb, prc, &_hwndView);
  306. if (SUCCEEDED(hr))
  307. {
  308. hr = psv->UIActivate(SVUIA_INPLACEACTIVATE);
  309. }
  310. }
  311. pvhb->Release();
  312. }
  313. else
  314. {
  315. hr = E_OUTOFMEMORY;
  316. }
  317. psv->Release();
  318. }
  319. for (int i = 0; SUCCEEDED(hr) && (i != cItems); i++)
  320. {
  321. LPCITEMIDLIST pidlChild = ILFindLastID(aItems[i]);
  322. hr = _pfv->SelectAndPositionItems(1, &pidlChild, NULL, SVSI_CHECK);
  323. }
  324. psf->Release();
  325. }
  326. FreeIDListArray(aItems, cItems);
  327. }
  328. pnsw->Release();
  329. }
  330. return hr;
  331. }
  332. STDAPI CFolderViewHost_CreateInstance(IUnknown *punkOut, REFIID riid, void **ppv)
  333. {
  334. CFolderViewHost *pfp = new CFolderViewHost();
  335. if (!pfp)
  336. return E_OUTOFMEMORY;
  337. HRESULT hr = pfp->QueryInterface(riid, ppv);
  338. pfp->Release();
  339. return hr;
  340. }