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.

896 lines
26 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. nwshmenu.cxx
  5. Abstract:
  6. This module implements the IContextMenu member functions necessary to support
  7. the context menu of NetWare shell extension.
  8. Author:
  9. Yi-Hsin Sung (yihsins) 25-Oct-1995
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <shellapi.h>
  16. #include <shlobj.h>
  17. #define DONT_WANT_SHELLDEBUG
  18. #include <shlobjp.h>
  19. #include <winnetwk.h>
  20. #include <ntddnwfs.h>
  21. //extern "C"
  22. //{
  23. #include "nwshrc.h"
  24. #include "nwwks.h"
  25. #include "nwutil.h"
  26. //}
  27. #include "nwshcmn.h"
  28. #include "nwshext.h"
  29. #define MAX_VERB_SIZE 128
  30. #define MAX_SHELL_IDLIST_SIZE 512
  31. BOOL g_cfNetResource = 0; // Clipboard format
  32. BOOL g_cfIDList = 0;
  33. NWMENUITEM aServerVerbs[] = { { IDO_VERB_WHOAMI, 0 },
  34. { IDO_VERB_LOGOUT, 0 },
  35. { IDO_VERB_ATTACHAS, 0 },
  36. { 0, 0 } };
  37. NWMENUITEM aDSVerbs[] = { { IDO_VERB_TREEWHOAMI, 0 },
  38. // { IDO_VERB_SETDEFAULTCONTEXT, 0 },
  39. { 0, 0 } };
  40. NWMENUITEM aDSTreeVerbs[] = { { IDO_VERB_TREEWHOAMI, 0 },
  41. { 0, 0 } };
  42. NWMENUITEM aGlobalVerbs[] = { { IDO_VERB_GLOBALWHOAMI, 0 },
  43. { 0, 0 } };
  44. NWMENUITEM aDirectoryVerbs[] = { { IDO_VERB_MAPNETWORKDRIVE, 0 },
  45. { 0, 0 } };
  46. NWMENUITEM aHoodVerbs[] = { { IDO_VERB_GLOBALWHOAMI, 0 },
  47. { 0, 0 } };
  48. HRESULT
  49. InsertCommandsArray( HMENU hMenu,
  50. UINT indexMenu,
  51. UINT idCmdFirst,
  52. LPNWMENUITEM aVerbs );
  53. UINT
  54. LookupCommand( LPNWMENUITEM aVerbs,
  55. LPCSTR pszCmd );
  56. UINT
  57. LookupResource( LPNWMENUITEM aVerbs,
  58. UINT uiResourceOffset );
  59. UINT WINAPI
  60. HIDA_GetIDList( LPIDA hida,
  61. UINT i,
  62. LPITEMIDLIST pidlOut,
  63. UINT cbMax);
  64. //
  65. // FUNCTION: CNWObjContextMenu::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
  66. //
  67. // PURPOSE: Called by the shell just before the context menu is displayed.
  68. // This is where you add your specific menu items.
  69. //
  70. // PARAMETERS:
  71. // hMenu - Handle to the context menu
  72. // indexMenu - Index of where to begin inserting menu items
  73. // idCmdFirst - Lowest value for new menu ID's
  74. // idCmtLast - Highest value for new menu ID's
  75. // uFlags - Specifies the context of the menu event
  76. //
  77. // RETURN VALUE:
  78. //
  79. //
  80. // COMMENTS:
  81. //
  82. STDMETHODIMP CNWObjContextMenu::QueryContextMenu( HMENU hMenu,
  83. UINT indexMenu,
  84. UINT idCmdFirst,
  85. UINT idCmdLast,
  86. UINT uFlags )
  87. {
  88. HRESULT hres;
  89. LPNETRESOURCE pNetRes = (LPNETRESOURCE) _buffer;
  90. if ( !::GetNetResourceFromShell( _pDataObj,
  91. pNetRes,
  92. sizeof( _buffer )))
  93. {
  94. // We cannot get the net resource of the selected object.
  95. // Must return number of menu items we added.
  96. // Nothing added here.
  97. return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 0 ));
  98. }
  99. // First, add a menu separator
  100. if ( InsertMenu( hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL))
  101. indexMenu++;
  102. // Next, add menu items depending on display types
  103. switch ( pNetRes->dwDisplayType )
  104. {
  105. case RESOURCEDISPLAYTYPE_ROOT:
  106. case RESOURCEDISPLAYTYPE_NETWORK:
  107. hres = InsertCommandsArray( hMenu, indexMenu,
  108. idCmdFirst, _pIdTable = aGlobalVerbs );
  109. break;
  110. case RESOURCEDISPLAYTYPE_TREE:
  111. hres = InsertCommandsArray( hMenu, indexMenu,
  112. idCmdFirst, _pIdTable = aDSTreeVerbs );
  113. break;
  114. case RESOURCEDISPLAYTYPE_NDSCONTAINER:
  115. hres = InsertCommandsArray( hMenu, indexMenu,
  116. idCmdFirst, _pIdTable = aDSVerbs );
  117. break;
  118. case RESOURCEDISPLAYTYPE_SERVER:
  119. {
  120. // Do we need to check if the server name is local
  121. // and disallow operation???
  122. hres = InsertCommandsArray( hMenu, indexMenu,
  123. idCmdFirst, _pIdTable = aServerVerbs );
  124. if (!SUCCEEDED(hres))
  125. break;
  126. LPBYTE pBuffer = NULL;
  127. DWORD EntriesRead = 0;
  128. DWORD_PTR ResumeKey = 0;
  129. WCHAR szServerName[MAX_PATH + 1];
  130. NwExtractServerName( pNetRes->lpRemoteName, szServerName );
  131. // See if we are connected.
  132. DWORD err = NwGetConnectionStatus( szServerName,
  133. &ResumeKey,
  134. &pBuffer,
  135. &EntriesRead );
  136. if ( err == NO_ERROR && EntriesRead > 0 )
  137. {
  138. PCONN_STATUS pConnStatus = (PCONN_STATUS) pBuffer;
  139. ASSERT( EntriesRead == 1 );
  140. if ( pConnStatus->fPreferred )
  141. {
  142. // This is a implicit preferred server connection
  143. // so, don't show the connection and don't let the user
  144. // logout of it since rdr doesn't allow it.
  145. ::EnableMenuItem( hMenu,
  146. LookupResource( aServerVerbs,
  147. IDO_VERB_LOGOUT),
  148. MF_GRAYED | MF_BYCOMMAND);
  149. }
  150. else if ( pConnStatus->fNds )
  151. {
  152. BOOL fInDefaultTree = FALSE;
  153. err = NwIsServerInDefaultTree( pNetRes->lpRemoteName, &fInDefaultTree );
  154. if ( (err == NO_ERROR) && fInDefaultTree )
  155. {
  156. // NDS connection and in the default tree, disable the Attach As button
  157. ::EnableMenuItem( hMenu,
  158. LookupResource( aServerVerbs,
  159. IDO_VERB_ATTACHAS),
  160. MF_GRAYED | MF_BYCOMMAND );
  161. }
  162. }
  163. }
  164. else
  165. {
  166. // If we are not attached or if error occurred when getting
  167. // connection status, then disable the Logout button.
  168. ::EnableMenuItem( hMenu,
  169. LookupResource( aServerVerbs,
  170. IDO_VERB_LOGOUT),
  171. MF_GRAYED | MF_BYCOMMAND);
  172. }
  173. if ( pBuffer != NULL )
  174. {
  175. LocalFree( pBuffer );
  176. pBuffer = NULL;
  177. }
  178. break;
  179. }
  180. default:
  181. // Must return number of menu items we added.
  182. // Nothing added here.
  183. hres = ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 0 ));
  184. break;
  185. }
  186. return hres;
  187. }
  188. //
  189. // FUNCTION: CNWObjContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO)
  190. //
  191. // PURPOSE: Called by the shell after the user has selected on of the
  192. // menu items that was added in QueryContextMenu().
  193. //
  194. // PARAMETERS:
  195. // lpcmi - Pointer to an CMINVOKECOMMANDINFO structure
  196. //
  197. // RETURN VALUE:
  198. //
  199. //
  200. // COMMENTS:
  201. //
  202. STDMETHODIMP CNWObjContextMenu::InvokeCommand( LPCMINVOKECOMMANDINFO lpcmi )
  203. {
  204. HRESULT hres = ResultFromScode(E_INVALIDARG);
  205. UINT idCmd = LookupCommand( _pIdTable , lpcmi->lpVerb );
  206. if ( !idCmd )
  207. return hres;
  208. LPNETRESOURCE pNetRes = (LPNETRESOURCE) _buffer;
  209. switch ( idCmd )
  210. {
  211. case IDO_VERB_GLOBALWHOAMI:
  212. hres = NWUIGlobalWhoAmI( lpcmi->hwnd );
  213. break;
  214. case IDO_VERB_TREEWHOAMI:
  215. hres = NWUIWhoAmI( lpcmi->hwnd, pNetRes );
  216. break;
  217. #if 0
  218. case IDO_VERB_SETDEFAULTCONTEXT:
  219. hres = NWUISetDefaultContext( lpcmi->hwnd, pNetRes );
  220. break;
  221. #endif
  222. case IDO_VERB_WHOAMI:
  223. hres = NWUIWhoAmI( lpcmi->hwnd, pNetRes );
  224. break;
  225. case IDO_VERB_LOGOUT:
  226. {
  227. BOOL fDisconnected = FALSE;
  228. hres = NWUILogOut( lpcmi->hwnd, pNetRes, &fDisconnected );
  229. if ( hres == NOERROR && fDisconnected )
  230. {
  231. // Logout is successful, need to notify shell
  232. FORMATETC fmte = { g_cfIDList ? g_cfIDList
  233. : (g_cfIDList=RegisterClipboardFormat( CFSTR_SHELLIDLIST)),
  234. (DVTARGETDEVICE FAR *)NULL,
  235. DVASPECT_CONTENT,
  236. -1,
  237. TYMED_HGLOBAL };
  238. STGMEDIUM medium;
  239. hres = _pDataObj->GetData( &fmte, &medium);
  240. if (SUCCEEDED(hres))
  241. {
  242. // We got pointer to IDList
  243. LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
  244. if ( pida )
  245. {
  246. BYTE BufIDList[MAX_SHELL_IDLIST_SIZE];
  247. LPITEMIDLIST pidl = (LPITEMIDLIST) BufIDList;
  248. if ( pidl )
  249. {
  250. // Convert IDA to IDList for this call
  251. HIDA_GetIDList( pida,
  252. 0, // One object should present
  253. pidl ,
  254. MAX_SHELL_IDLIST_SIZE);
  255. // Call SHchangeNotify
  256. g_pFuncSHChangeNotify( SHCNE_SERVERDISCONNECT,
  257. SHCNF_IDLIST,
  258. pidl,
  259. NULL);
  260. }
  261. GlobalUnlock(medium.hGlobal);
  262. }
  263. }
  264. }
  265. break;
  266. }
  267. case IDO_VERB_ATTACHAS:
  268. hres = NWUIAttachAs( lpcmi->hwnd, pNetRes );
  269. break;
  270. }
  271. return hres;
  272. }
  273. //
  274. // FUNCTION: CNWObjContextMenu::GetCommandString( UINT, UINT, UINT FAR *, LPSTR, UINT )
  275. //
  276. // PURPOSE: Called by the shell after the user has selected on of the
  277. // menu items that was added in QueryContextMenu().
  278. //
  279. // PARAMETERS:
  280. //
  281. // RETURN VALUE:
  282. //
  283. //
  284. // COMMENTS:
  285. //
  286. STDMETHODIMP CNWObjContextMenu::GetCommandString( UINT_PTR idCmd,
  287. UINT uFlags,
  288. UINT FAR *reserved,
  289. LPSTR pszName,
  290. UINT cchMax )
  291. {
  292. if ( uFlags == GCS_HELPTEXT && _pIdTable != NULL )
  293. {
  294. ::LoadString( ::hmodNW,
  295. IDS_VERBS_HELP_BASE + _pIdTable[idCmd].idResourceString,
  296. (LPWSTR) pszName,
  297. cchMax );
  298. return NOERROR;
  299. }
  300. return E_NOTIMPL;
  301. }
  302. //
  303. // FUNCTION: CNWFldContextMenu::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
  304. //
  305. // PURPOSE: Called by the shell just before the context menu is displayed.
  306. // This is where you add your specific menu items.
  307. //
  308. // PARAMETERS:
  309. // hMenu - Handle to the context menu
  310. // indexMenu - Index of where to begin inserting menu items
  311. // idCmdFirst - Lowest value for new menu ID's
  312. // idCmtLast - Highest value for new menu ID's
  313. // uFlags - Specifies the context of the menu event
  314. //
  315. // RETURN VALUE:
  316. //
  317. //
  318. // COMMENTS:
  319. //
  320. STDMETHODIMP CNWFldContextMenu::QueryContextMenu( HMENU hMenu,
  321. UINT indexMenu,
  322. UINT idCmdFirst,
  323. UINT idCmdLast,
  324. UINT uFlags )
  325. {
  326. UINT idCmd = idCmdFirst;
  327. if ( IsNetWareObject() )
  328. {
  329. WCHAR szFullPath[MAX_PATH+1];
  330. if ( GetFSObject( szFullPath, sizeof( szFullPath )) == NOERROR )
  331. {
  332. BOOL fUNC = FALSE;
  333. // Check if the name at least contains the "\\server\share\dir"
  334. // We need to add "Map Network Drive" menu in this case.
  335. if (( szFullPath[0] == L'\\') && ( szFullPath[1] == L'\\'))
  336. {
  337. LPWSTR pszLastSlash = wcschr( szFullPath + 2, L'\\');
  338. if ( pszLastSlash )
  339. pszLastSlash = wcschr( pszLastSlash+1, L'\\');
  340. if ( pszLastSlash != NULL )
  341. fUNC = TRUE;
  342. }
  343. if ( fUNC )
  344. {
  345. LPNETRESOURCE pNetRes = (LPNETRESOURCE) _buffer;
  346. WCHAR szProvider[MAX_PATH+1];
  347. // Build a net resource that can be used to connect
  348. // store the provider name first
  349. wcscpy( szProvider, pNetRes->lpProvider );
  350. // zero out the memory cause it is filled by IsNetWareObject
  351. RtlZeroMemory( pNetRes, sizeof(NETRESOURCE));
  352. pNetRes->dwType = RESOURCETYPE_DISK;
  353. pNetRes->lpRemoteName = (LPWSTR) ((DWORD_PTR)pNetRes + sizeof(NETRESOURCE));
  354. wcscpy( pNetRes->lpRemoteName, szFullPath );
  355. pNetRes->lpProvider = (LPWSTR) ((DWORD_PTR)pNetRes->lpRemoteName + (wcslen(szFullPath)+1)*sizeof(WCHAR));
  356. wcscpy( pNetRes->lpProvider, szProvider );
  357. if ( InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL))
  358. {
  359. indexMenu++;
  360. }
  361. return InsertCommandsArray( hMenu, indexMenu,
  362. idCmdFirst, aDirectoryVerbs );
  363. }
  364. }
  365. }
  366. // Must return number of menu items we added.
  367. // Nothing added here.
  368. return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, 0 ));
  369. }
  370. //
  371. // FUNCTION: CNWFldContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO)
  372. //
  373. // PURPOSE: Called by the shell after the user has selected on of the
  374. // menu items that was added in QueryContextMenu().
  375. //
  376. // PARAMETERS:
  377. // lpcmi - Pointer to an CMINVOKECOMMANDINFO structure
  378. //
  379. // RETURN VALUE:
  380. //
  381. //
  382. // COMMENTS:
  383. //
  384. STDMETHODIMP CNWFldContextMenu::InvokeCommand( LPCMINVOKECOMMANDINFO lpcmi )
  385. {
  386. HRESULT hres = ResultFromScode(E_INVALIDARG);
  387. UINT idCmd = LookupCommand( aDirectoryVerbs , lpcmi->lpVerb );
  388. if ( !idCmd )
  389. return hres;
  390. LPNETRESOURCE pNetRes = (LPNETRESOURCE) _buffer;
  391. switch ( idCmd )
  392. {
  393. case IDO_VERB_MAPNETWORKDRIVE:
  394. hres = NWUIMapNetworkDrive( lpcmi->hwnd, pNetRes );
  395. break;
  396. }
  397. return hres;
  398. }
  399. //
  400. // FUNCTION: CNWFldContextMenu::GetCommandString( UINT, UINT, UINT FAR *, LPSTR, UINT )
  401. //
  402. // PURPOSE: Called by the shell after the user has selected on of the
  403. // menu items that was added in QueryContextMenu().
  404. //
  405. // PARAMETERS:
  406. //
  407. // RETURN VALUE:
  408. //
  409. //
  410. // COMMENTS:
  411. //
  412. STDMETHODIMP CNWFldContextMenu::GetCommandString( UINT_PTR idCmd,
  413. UINT uFlags,
  414. UINT FAR *reserved,
  415. LPSTR pszName,
  416. UINT cchMax )
  417. {
  418. if ( uFlags == GCS_HELPTEXT )
  419. {
  420. ::LoadString( ::hmodNW,
  421. IDS_VERBS_HELP_BASE + IDO_VERB_MAPNETWORKDRIVE,
  422. (LPWSTR) pszName,
  423. cchMax );
  424. return NOERROR;
  425. }
  426. return E_NOTIMPL;
  427. }
  428. //
  429. // Method checks if the selected object belongs the netware provider
  430. //
  431. BOOL CNWFldContextMenu::IsNetWareObject( VOID )
  432. {
  433. LPNETRESOURCE pNetRes = (LPNETRESOURCE) _buffer;
  434. if ( !::GetNetResourceFromShell( _pDataObj,
  435. pNetRes,
  436. sizeof(_buffer)))
  437. {
  438. // Cannot get the NETRESOURCE of the selected object,
  439. // hence assume that the object is not a NetWare object.
  440. return FALSE;
  441. }
  442. if ( ( pNetRes->lpProvider != NULL )
  443. && ( _wcsicmp( pNetRes->lpProvider, g_szProviderName ) == 0 )
  444. )
  445. {
  446. return TRUE;
  447. }
  448. return FALSE;
  449. }
  450. //
  451. // Method obtains file system name associated with selected shell object
  452. //
  453. HRESULT CNWFldContextMenu::GetFSObject( LPWSTR pszPath, UINT cbMaxPath )
  454. {
  455. FORMATETC fmte = { CF_HDROP,
  456. (DVTARGETDEVICE FAR *) NULL,
  457. DVASPECT_CONTENT,
  458. -1,
  459. TYMED_HGLOBAL };
  460. STGMEDIUM medium;
  461. HRESULT hres = _pDataObj->GetData( &fmte, &medium);
  462. if (SUCCEEDED(hres))
  463. {
  464. if ( g_pFuncSHDragQueryFile )
  465. {
  466. HDROP hdrop = (HDROP) medium.hGlobal;
  467. UINT cFiles = (*g_pFuncSHDragQueryFile)( hdrop, (UINT)-1, NULL, 0 );
  468. (*g_pFuncSHDragQueryFile)( hdrop, 0, pszPath, cbMaxPath );
  469. ODS(L"CNWFldContextMenu::GetFSObject()\n");
  470. ODS( pszPath );
  471. ODS(L"\n");
  472. }
  473. //
  474. // HACK: We are supposed to call ReleaseStgMedium. This is a temporary
  475. // hack until OLE 2.01 for Chicago is released.
  476. //
  477. if (medium.pUnkForRelease)
  478. {
  479. medium.pUnkForRelease->Release();
  480. }
  481. else
  482. {
  483. GlobalFree(medium.hGlobal);
  484. }
  485. }
  486. return hres;
  487. }
  488. // FUNCTION: CNWHoodContextMenu::QueryContextMenu(HMENU, UINT, UINT, UINT, UINT)
  489. //
  490. // PURPOSE: Called by the shell just before the context menu is displayed.
  491. // This is where you add your specific menu items.
  492. //
  493. // PARAMETERS:
  494. // hMenu - Handle to the context menu
  495. // indexMenu - Index of where to begin inserting menu items
  496. // idCmdFirst - Lowest value for new menu ID's
  497. // idCmtLast - Highest value for new menu ID's
  498. // uFlags - Specifies the context of the menu event
  499. //
  500. // RETURN VALUE:
  501. //
  502. //
  503. // COMMENTS:
  504. //
  505. STDMETHODIMP CNWHoodContextMenu::QueryContextMenu( HMENU hMenu,
  506. UINT indexMenu,
  507. UINT idCmdFirst,
  508. UINT idCmdLast,
  509. UINT uFlags )
  510. {
  511. // First, insert a menu separator
  512. if ( InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL))
  513. {
  514. indexMenu++;
  515. }
  516. // Then, insert the verbs
  517. return InsertCommandsArray( hMenu, indexMenu,
  518. idCmdFirst, aHoodVerbs );
  519. }
  520. //
  521. // FUNCTION: CNWHoodContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO)
  522. //
  523. // PURPOSE: Called by the shell after the user has selected on of the
  524. // menu items that was added in QueryContextMenu().
  525. //
  526. // PARAMETERS:
  527. // lpcmi - Pointer to an CMINVOKECOMMANDINFO structure
  528. //
  529. // RETURN VALUE:
  530. //
  531. //
  532. // COMMENTS:
  533. //
  534. STDMETHODIMP CNWHoodContextMenu::InvokeCommand( LPCMINVOKECOMMANDINFO lpcmi )
  535. {
  536. HRESULT hres = ResultFromScode(E_INVALIDARG);
  537. UINT idCmd = LookupCommand( aHoodVerbs , lpcmi->lpVerb );
  538. if ( !idCmd )
  539. return hres;
  540. switch ( idCmd )
  541. {
  542. case IDO_VERB_GLOBALWHOAMI:
  543. hres = NWUIGlobalWhoAmI( lpcmi->hwnd );
  544. break;
  545. }
  546. return hres;
  547. }
  548. //
  549. // FUNCTION: CNWHoodContextMenu::GetCommandString( UINT, UINT, UINT FAR *, LPSTR, UINT)
  550. //
  551. // PURPOSE: Called by the shell after the user has selected on of the
  552. // menu items that was added in QueryContextMenu().
  553. //
  554. // PARAMETERS:
  555. //
  556. // RETURN VALUE:
  557. //
  558. //
  559. // COMMENTS:
  560. //
  561. STDMETHODIMP CNWHoodContextMenu::GetCommandString( UINT_PTR idCmd,
  562. UINT uFlags,
  563. UINT FAR *reserved,
  564. LPSTR pszName,
  565. UINT cchMax )
  566. {
  567. if ( uFlags == GCS_HELPTEXT )
  568. {
  569. ::LoadString( ::hmodNW,
  570. IDS_VERBS_HELP_BASE + IDO_VERB_GLOBALWHOAMI,
  571. (LPWSTR) pszName,
  572. cchMax );
  573. return NOERROR;
  574. }
  575. return E_NOTIMPL;
  576. }
  577. //
  578. // Method gets the NETRESOURCE of the selected object
  579. //
  580. BOOL GetNetResourceFromShell( LPDATAOBJECT pDataObj,
  581. LPNETRESOURCE pNetRes,
  582. UINT dwBufferSize )
  583. {
  584. FORMATETC fmte = { g_cfNetResource ? g_cfNetResource
  585. : (g_cfNetResource=RegisterClipboardFormat(CFSTR_NETRESOURCES)),
  586. (DVTARGETDEVICE FAR *) NULL,
  587. DVASPECT_CONTENT,
  588. -1,
  589. TYMED_HGLOBAL };
  590. STGMEDIUM medium;
  591. UINT cItems;
  592. if ( pNetRes == NULL )
  593. return FALSE;
  594. memset( pNetRes, 0, dwBufferSize );
  595. if ( !g_pFuncSHGetNetResource ) // Not loaded
  596. return FALSE;
  597. HRESULT hres = pDataObj->GetData( &fmte, &medium );
  598. if (!SUCCEEDED(hres))
  599. return FALSE;
  600. HNRES hnres = medium.hGlobal;
  601. // Get the number of selected items
  602. cItems = (*g_pFuncSHGetNetResource)( hnres, (UINT)-1, NULL, 0);
  603. if ( cItems == 0 ) // Nothing selected
  604. return FALSE;
  605. // Get the NETRESOURCE of the first item
  606. (*g_pFuncSHGetNetResource)( hnres, 0, pNetRes, dwBufferSize);
  607. #if DBG
  608. WCHAR szTemp[32];
  609. wsprintf(szTemp, L"DisplayType = %d\n", pNetRes->dwDisplayType );
  610. ODS(L"\n**** GetNetResourceFromShell ***\n");
  611. ODS(pNetRes->lpProvider );
  612. ODS(L"\n");
  613. ODS(pNetRes->lpRemoteName );
  614. ODS(L"\n");
  615. ODS(szTemp );
  616. ODS(L"\n\n");
  617. #endif
  618. //
  619. // HACK: We are supposed to call ReleaseStgMedium. This is a temporary
  620. // hack until OLE 2.01 for Chicago is released.
  621. //
  622. if (medium.pUnkForRelease)
  623. {
  624. medium.pUnkForRelease->Release();
  625. }
  626. else
  627. {
  628. GlobalFree(medium.hGlobal);
  629. }
  630. return TRUE;
  631. }
  632. //-------------------------------------------------------------------//
  633. HRESULT InsertCommandsArray( HMENU hMenu,
  634. UINT indexMenu,
  635. UINT idCmdFirst,
  636. LPNWMENUITEM aVerbs )
  637. {
  638. UINT idNewCmdFirst = idCmdFirst;
  639. WCHAR szVerb[MAX_VERB_SIZE];
  640. for ( int i = 0; aVerbs[i].idResourceString ; i++)
  641. {
  642. if ( ::LoadString( ::hmodNW,
  643. aVerbs[i].idResourceString + IDS_VERBS_BASE,
  644. szVerb,
  645. sizeof(szVerb)/sizeof(szVerb[0])))
  646. {
  647. if (::InsertMenu( hMenu,
  648. indexMenu,
  649. MF_STRING | MF_BYPOSITION,
  650. idNewCmdFirst,
  651. szVerb))
  652. {
  653. // Add command id to the array
  654. aVerbs[i].idCommand = idNewCmdFirst;
  655. // Update command id and index
  656. idNewCmdFirst++;
  657. if (indexMenu != (UINT)-1)
  658. indexMenu++;
  659. }
  660. }
  661. }
  662. return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS,
  663. FACILITY_NULL,
  664. (USHORT)(idNewCmdFirst-idCmdFirst)));
  665. }
  666. UINT LookupCommand( LPNWMENUITEM aVerbs, LPCSTR pszCmd )
  667. {
  668. if ((UINT_PTR)pszCmd > 0xFFFF)
  669. {
  670. // Possible that shell will use string commands, but unlikely
  671. WCHAR szVerb[MAX_VERB_SIZE];
  672. for ( int i=0; aVerbs[i].idResourceString; i++)
  673. {
  674. if ( ::LoadString( ::hmodNW,
  675. aVerbs[i].idResourceString + IDS_VERBS_BASE,
  676. szVerb,
  677. sizeof(szVerb)/sizeof(szVerb[0])))
  678. {
  679. if( ::lstrcmpi( (LPCWSTR) pszCmd, szVerb) == 0)
  680. return( aVerbs[i].idResourceString);
  681. }
  682. }
  683. return 0;
  684. }
  685. else
  686. {
  687. return( aVerbs[LOWORD(pszCmd)].idResourceString);
  688. }
  689. }
  690. UINT LookupResource( LPNWMENUITEM aVerbs, UINT uiResourceOffset )
  691. {
  692. for ( int i = 0; aVerbs[i].idResourceString; i++ )
  693. {
  694. if ( aVerbs[i].idResourceString == uiResourceOffset )
  695. return aVerbs[i].idCommand;
  696. }
  697. return 0;
  698. }
  699. //-------------------------------------------------------------------//
  700. #define _ILSkip(pidl, cb) ((LPITEMIDLIST)(((BYTE*)(pidl))+cb))
  701. #define _ILNext(pidl) _ILSkip(pidl, (pidl)->mkid.cb)
  702. #define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
  703. #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
  704. static
  705. UINT WINAPI MyILGetSize(LPCITEMIDLIST pidl)
  706. {
  707. UINT cbTotal = 0;
  708. if (pidl)
  709. {
  710. cbTotal += sizeof(pidl->mkid.cb); // Null terminator
  711. while (pidl->mkid.cb)
  712. {
  713. cbTotal += pidl->mkid.cb;
  714. pidl = _ILNext(pidl);
  715. }
  716. }
  717. return cbTotal;
  718. }
  719. UINT WINAPI HIDA_GetIDList( LPIDA hida, UINT i, LPITEMIDLIST pidlOut, UINT cbMax)
  720. {
  721. LPCITEMIDLIST pidlFolder = HIDA_GetPIDLFolder((LPIDA)hida);
  722. LPCITEMIDLIST pidlItem = HIDA_GetPIDLItem((LPIDA)hida, i);
  723. UINT cbFolder = MyILGetSize(pidlFolder)-sizeof(USHORT);
  724. UINT cbItem = MyILGetSize(pidlItem);
  725. if (cbMax < cbFolder+cbItem)
  726. {
  727. if (pidlOut)
  728. pidlOut->mkid.cb = 0;
  729. }
  730. else
  731. {
  732. memmove(pidlOut, pidlFolder, cbFolder);
  733. memmove(((LPBYTE)pidlOut)+cbFolder, pidlItem, cbItem);
  734. }
  735. return (cbFolder+cbItem);
  736. }