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.

583 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: share.cxx
  7. //
  8. // Contents: Shell extension handler for sharing
  9. //
  10. // Classes: CShare
  11. //
  12. // History: 4-Apr-95 BruceFo Created
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "headers.hxx"
  16. #pragma hdrstop
  17. #include "shrpage.hxx"
  18. #include "shrpage2.hxx"
  19. #include "share.hxx"
  20. #include "acl.hxx"
  21. #include "util.hxx"
  22. #include "resource.h"
  23. //--------------------------------------------------------------------------
  24. //+-------------------------------------------------------------------------
  25. //
  26. // Member: CShare::CShare
  27. //
  28. // Synopsis: Constructor
  29. //
  30. // History: 4-Apr-95 BruceFo Created
  31. //
  32. //--------------------------------------------------------------------------
  33. CShare::CShare(VOID) :
  34. _uRefs(1),
  35. _fPathChecked(FALSE),
  36. _fMultipleSharesSelected (FALSE)
  37. {
  38. INIT_SIG(CShare);
  39. _szPath[0] = 0;
  40. }
  41. //+-------------------------------------------------------------------------
  42. //
  43. // Member: CShare::~CShare
  44. //
  45. // Synopsis: Destructor
  46. //
  47. // History: 4-Apr-95 BruceFo Created
  48. //
  49. //--------------------------------------------------------------------------
  50. CShare::~CShare()
  51. {
  52. CHECK_SIG(CShare);
  53. }
  54. #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
  55. LPCITEMIDLIST IDA_GetIDListPtr(LPIDA pida, UINT i)
  56. {
  57. if (i == (UINT)-1 || i < pida->cidl)
  58. {
  59. return HIDA_GetPIDLItem(pida, i);
  60. }
  61. return NULL;
  62. }
  63. //
  64. // Retrieve a PIDL from the HIDA.
  65. //
  66. STDAPI_(LPITEMIDLIST)
  67. IDA_FullIDList(
  68. CIDA * pidaIn
  69. , UINT idxIn
  70. )
  71. {
  72. LPITEMIDLIST pidl = NULL;
  73. LPCITEMIDLIST pidlParent = IDA_GetIDListPtr( pidaIn, (UINT) -1 );
  74. if ( NULL != pidlParent )
  75. {
  76. LPCITEMIDLIST pidlRel = IDA_GetIDListPtr( pidaIn, idxIn );
  77. if ( NULL != pidlRel )
  78. {
  79. pidl = ILCombine( pidlParent, pidlRel );
  80. }
  81. }
  82. return pidl;
  83. }
  84. //
  85. // Use LocalFree( ) to free the ppidaOut returned here
  86. //
  87. // Return Values:
  88. // S_OK
  89. // Successfully extracted and copied the HIDA.
  90. //
  91. // E_OUTOFMEMORY
  92. // Failed to copy the HIDA.
  93. //
  94. // other HRESULTs
  95. //
  96. HRESULT
  97. DataObj_CopyHIDA(
  98. IDataObject * pdtobjIn
  99. , CIDA ** ppidaOut
  100. )
  101. {
  102. HRESULT hr;
  103. STGMEDIUM medium;
  104. static CLIPFORMAT g_cfHIDA = 0;
  105. FORMATETC fmte = { 0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  106. // Check parameters
  107. appAssert( NULL != pdtobjIn );
  108. appAssert( NULL != ppidaOut );
  109. // Clear out parameter
  110. *ppidaOut = NULL;
  111. //
  112. // Register clip format if not already done.
  113. //
  114. if ( 0 == g_cfHIDA )
  115. {
  116. g_cfHIDA = (CLIPFORMAT) RegisterClipboardFormat( CFSTR_SHELLIDLIST );
  117. }
  118. fmte.cfFormat = g_cfHIDA;
  119. //
  120. // Retrieve HIDA
  121. //
  122. hr = pdtobjIn->GetData( &fmte, &medium );
  123. if ( SUCCEEDED( hr ) )
  124. {
  125. SIZE_T sizet = GlobalSize( medium.hGlobal );
  126. if ( (~((DWORD) 0)) > sizet )
  127. {
  128. DWORD cb = (DWORD) sizet;
  129. CIDA * pida = (CIDA *) LocalAlloc( 0, cb );
  130. if ( NULL != pida )
  131. {
  132. void * pv = GlobalLock( medium.hGlobal );
  133. CopyMemory( pida, pv, cb );
  134. GlobalUnlock( medium.hGlobal );
  135. *ppidaOut = pida;
  136. }
  137. else
  138. {
  139. hr = E_OUTOFMEMORY;
  140. }
  141. }
  142. else
  143. {
  144. hr = E_OUTOFMEMORY;
  145. }
  146. ReleaseStgMedium( &medium );
  147. }
  148. return hr;
  149. }
  150. //
  151. // Helpers to banish STRRET's into the realm of darkness
  152. //
  153. STDAPI DisplayNameOf(IShellFolder *psf, LPCITEMIDLIST pidl, DWORD flags, LPTSTR psz, UINT cch)
  154. {
  155. *psz = 0;
  156. STRRET sr;
  157. HRESULT hr = psf->GetDisplayNameOf(pidl, flags, &sr);
  158. if (SUCCEEDED(hr))
  159. hr = StrRetToBuf(&sr, pidl, psz, cch);
  160. return hr;
  161. }
  162. //+-------------------------------------------------------------------------
  163. //
  164. // Member: CShare::Initialize
  165. //
  166. // Derivation: IShellExtInit
  167. //
  168. // Synopsis: Initialize the shell extension. Stashes away the argument data.
  169. //
  170. // History: 4-Apr-95 BruceFo Created
  171. //
  172. // Notes: This method can be called more than once.
  173. //
  174. //--------------------------------------------------------------------------
  175. STDMETHODIMP
  176. CShare::Initialize(
  177. LPCITEMIDLIST pidlFolder,
  178. LPDATAOBJECT pDataObject,
  179. HKEY hkeyProgID
  180. )
  181. {
  182. CHECK_SIG(CShare);
  183. HRESULT hr = E_FAIL;
  184. if (pDataObject && _szPath[0] == 0)
  185. {
  186. STGMEDIUM medium;
  187. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  188. hr = pDataObject->GetData(&fmte, &medium);
  189. if (SUCCEEDED(hr))
  190. {
  191. // Get the count of shares that have been selected. Display the page only
  192. // if 1 share is selected but not for multiple shares.
  193. UINT nCntFiles = ::DragQueryFile ((HDROP) medium.hGlobal, -1, _szPath, ARRAYLEN (_szPath));
  194. if ( nCntFiles > 1 )
  195. {
  196. _fMultipleSharesSelected = TRUE;
  197. }
  198. DragQueryFile((HDROP)medium.hGlobal, 0, _szPath, ARRAYLEN(_szPath));
  199. ReleaseStgMedium(&medium);
  200. hr = S_OK;
  201. }
  202. }
  203. if (FAILED(hr) && _szPath[0] == 0 )
  204. {
  205. LPIDA pida;
  206. hr = DataObj_CopyHIDA(pDataObject, &pida);
  207. if (SUCCEEDED(hr))
  208. {
  209. if (pida->cidl > 1)
  210. {
  211. _fMultipleSharesSelected = TRUE;
  212. }
  213. // Only grab the first guy.
  214. LPITEMIDLIST pidl = IDA_FullIDList( pida, 0 );
  215. if ( NULL != pidl )
  216. {
  217. LPCITEMIDLIST pidlParent = IDA_GetIDListPtr( pida, (UINT) -1 );
  218. if (NULL != pidlParent)
  219. {
  220. IShellFolder * psf;
  221. LPCITEMIDLIST pidlLast;
  222. hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&psf, &pidlLast);
  223. if (SUCCEEDED(hr))
  224. {
  225. hr = DisplayNameOf(psf, pidlLast, SHGDN_NORMAL | SHGDN_FORPARSING, _szPath, ARRAYLEN(_szPath));
  226. psf->Release();
  227. }
  228. }
  229. }
  230. LocalFree(pida);
  231. }
  232. }
  233. return hr;
  234. }
  235. //+-------------------------------------------------------------------------
  236. //
  237. // Member: CShare::AddPages
  238. //
  239. // Derivation: IShellPropSheetExt
  240. //
  241. // Synopsis: (from shlobj.h)
  242. // "The explorer calls this member function when it finds a
  243. // registered property sheet extension for a particular type
  244. // of object. For each additional page, the extension creates
  245. // a page object by calling CreatePropertySheetPage API and
  246. // calls lpfnAddPage.
  247. //
  248. // Arguments: lpfnAddPage -- Specifies the callback function.
  249. // lParam -- Specifies the opaque handle to be passed to the
  250. // callback function.
  251. //
  252. // History: 4-Apr-95 BruceFo Created
  253. //
  254. //--------------------------------------------------------------------------
  255. STDMETHODIMP
  256. CShare::AddPages(
  257. LPFNADDPROPSHEETPAGE lpfnAddPage,
  258. LPARAM lParam
  259. )
  260. {
  261. CHECK_SIG(CShare);
  262. if (!_fMultipleSharesSelected && _OKToShare())
  263. {
  264. appAssert(_szPath[0]);
  265. //
  266. // Create a property sheet page object from a dialog box.
  267. //
  268. PWSTR pszPath = NewDup(_szPath);
  269. if (NULL == pszPath)
  270. {
  271. return E_OUTOFMEMORY;
  272. }
  273. // Now we have pszPath memory to delete
  274. BOOL bSimpleUI = IsSimpleUI();
  275. CShareBase* pPage = NULL;
  276. if (bSimpleUI)
  277. {
  278. pPage = new CSimpleSharingPage(pszPath);
  279. }
  280. else
  281. {
  282. pPage = new CSharingPropertyPage(pszPath, FALSE);
  283. }
  284. if (NULL == pPage)
  285. {
  286. delete[] pszPath;
  287. return E_OUTOFMEMORY;
  288. }
  289. // Now the pPage object owns pszPath memory. However, we have
  290. // pPage memory to delete.
  291. HRESULT hr = pPage->InitInstance();
  292. if (FAILED(hr))
  293. {
  294. pPage->Release();
  295. return E_OUTOFMEMORY;
  296. }
  297. PROPSHEETPAGE psp;
  298. psp.dwSize = sizeof(psp); // no extra data.
  299. psp.dwFlags = PSP_USEREFPARENT | PSP_USECALLBACK;
  300. psp.hInstance = g_hInstance;
  301. psp.pszTemplate = bSimpleUI ? MAKEINTRESOURCE(IDD_SIMPLE_SHARE_PROPERTIES) : MAKEINTRESOURCE(IDD_SHARE_PROPERTIES);
  302. psp.hIcon = NULL;
  303. psp.pszTitle = NULL;
  304. psp.pfnDlgProc = CShareBase::DlgProcPage;
  305. psp.lParam = (LPARAM)pPage; // transfer ownership
  306. psp.pfnCallback = CShareBase::PageCallback;
  307. psp.pcRefParent = &g_NonOLEDLLRefs;
  308. HPROPSHEETPAGE hpage = CreatePropertySheetPage(&psp);
  309. if (NULL == hpage)
  310. {
  311. // If CreatePropertySheetPage fails, we still have pPage memory
  312. // to delete.
  313. pPage->Release();
  314. return E_OUTOFMEMORY;
  315. }
  316. BOOL fAdded = (*lpfnAddPage)(hpage, lParam);
  317. if (!fAdded)
  318. {
  319. // At this point, pPage memory, as the lParam of a PROPSHEETPAGE
  320. // that has been converted into an HPROPSHEETPAGE, is owned by the
  321. // hpage. Calling DestroyPropertySheetPage will invoke the
  322. // PageCallback function, subsequently destroying the pPage object,
  323. // and hence the pszPath object within it. Whew!
  324. DestroyPropertySheetPage(hpage);
  325. return E_OUTOFMEMORY;
  326. }
  327. }
  328. return S_OK;
  329. }
  330. //+-------------------------------------------------------------------------
  331. //
  332. // Member: CShare::ReplacePages
  333. //
  334. // Derivation: IShellPropSheetExt
  335. //
  336. // Synopsis: (From shlobj.h)
  337. // "The explorer never calls this member of property sheet
  338. // extensions. The explorer calls this member of control panel
  339. // extensions, so that they can replace some of default control
  340. // panel pages (such as a page of mouse control panel)."
  341. //
  342. // Arguments: uPageID -- Specifies the page to be replaced.
  343. // lpfnReplace -- Specifies the callback function.
  344. // lParam -- Specifies the opaque handle to be passed to the
  345. // callback function.
  346. //
  347. // History: 4-Apr-95 BruceFo Created
  348. //
  349. //--------------------------------------------------------------------------
  350. STDMETHODIMP
  351. CShare::ReplacePage(
  352. UINT uPageID,
  353. LPFNADDPROPSHEETPAGE lpfnReplaceWith,
  354. LPARAM lParam
  355. )
  356. {
  357. CHECK_SIG(CShare);
  358. appAssert(!"CShare::ReplacePage called, not implemented");
  359. return E_NOTIMPL;
  360. }
  361. //+-------------------------------------------------------------------------
  362. //
  363. // Member: CShare::QueryContextMenu
  364. //
  365. // Derivation: IContextMenu
  366. //
  367. // Synopsis: Called when shell wants to add context menu items.
  368. //
  369. // History: 4-Apr-95 BruceFo Created
  370. //
  371. //--------------------------------------------------------------------------
  372. STDMETHODIMP
  373. CShare::QueryContextMenu(
  374. HMENU hmenu,
  375. UINT indexMenu,
  376. UINT idCmdFirst,
  377. UINT idCmdLast,
  378. UINT uFlags
  379. )
  380. {
  381. CHECK_SIG(CShare);
  382. if ((hmenu == NULL) || (uFlags & (CMF_DEFAULTONLY | CMF_VERBSONLY)))
  383. {
  384. return S_OK;
  385. }
  386. int cNumberAdded = 0;
  387. UINT idCmd = idCmdFirst;
  388. // 159891 remove context menu if multiple shares selected
  389. if (!_fMultipleSharesSelected && _OKToShare())
  390. {
  391. appAssert(_szPath[0]);
  392. WCHAR szShareMenuItem[50];
  393. LoadString(g_hInstance, IDS_SHARING, szShareMenuItem, ARRAYLEN(szShareMenuItem));
  394. if (InsertMenu(hmenu, indexMenu, MF_STRING | MF_BYPOSITION, idCmd++, szShareMenuItem))
  395. {
  396. cNumberAdded++;
  397. InsertMenu(hmenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);
  398. }
  399. }
  400. return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)cNumberAdded));
  401. }
  402. //+-------------------------------------------------------------------------
  403. //
  404. // Member: CShare::InvokeCommand
  405. //
  406. // Derivation: IContextMenu
  407. //
  408. // Synopsis: Called when the shell wants to invoke a context menu item.
  409. //
  410. // History: 4-Apr-95 BruceFo Created
  411. //
  412. //--------------------------------------------------------------------------
  413. STDMETHODIMP
  414. CShare::InvokeCommand(
  415. LPCMINVOKECOMMANDINFO pici
  416. )
  417. {
  418. CHECK_SIG(CShare);
  419. HRESULT hr = E_INVALIDARG; // assume error.
  420. if (0 == HIWORD(pici->lpVerb))
  421. {
  422. appAssert(_szPath[0]);
  423. hr = ShowShareFolderUIW(pici->hwnd, _szPath);
  424. }
  425. else
  426. {
  427. // FEATURE: compare the strings if not a MAKEINTRESOURCE?
  428. }
  429. return hr;
  430. }
  431. //+-------------------------------------------------------------------------
  432. //
  433. // Member: CShare::GetCommandString
  434. //
  435. // Derivation: IContextMenu
  436. //
  437. // Synopsis: Called when the shell wants to get a help string or the
  438. // menu string.
  439. //
  440. // History: 4-Apr-95 BruceFo Created
  441. //
  442. //--------------------------------------------------------------------------
  443. STDMETHODIMP
  444. CShare::GetCommandString(
  445. UINT_PTR idCmd,
  446. UINT uType,
  447. UINT* pwReserved,
  448. LPSTR pszName,
  449. UINT cchMax
  450. )
  451. {
  452. CHECK_SIG(CShare);
  453. if (uType == GCS_HELPTEXT)
  454. {
  455. LoadStringW(g_hInstance, IDS_MENUHELP, (LPWSTR)pszName, cchMax);
  456. return NOERROR;
  457. }
  458. else
  459. {
  460. LoadStringW(g_hInstance, IDS_SHARING, (LPWSTR)pszName, cchMax);
  461. return NOERROR;
  462. }
  463. }
  464. //+-------------------------------------------------------------------------
  465. //
  466. // Member: CShare::_OKToShare
  467. //
  468. // Synopsis: Determine if it is ok to share the current object. It stashes
  469. // away the current path by querying the cached IDataObject.
  470. //
  471. // History: 4-Apr-95 BruceFo Created
  472. //
  473. //--------------------------------------------------------------------------
  474. BOOL
  475. CShare::_OKToShare(VOID)
  476. {
  477. CHECK_SIG(CShare);
  478. if (!_fPathChecked)
  479. {
  480. _fPathChecked = TRUE;
  481. _fOkToSharePath = (S_OK == CanShareFolderW(_szPath));
  482. }
  483. return _fOkToSharePath;
  484. }
  485. // dummy function to export to get linking to work
  486. HRESULT SharePropDummyFunction()
  487. {
  488. return S_OK;
  489. }