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
22 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. nwshext.cxx
  5. Abstract:
  6. This module implements the basics of shell extension classes.
  7. It includes AddRef(), Release(), QueryInterface() of the
  8. following classes.
  9. CNWObjContextMenuClassFactory, CNWObjContextMenu
  10. CNWFldContextMenuClassFactory, CNWFldContextMenu
  11. CNWHoodContextMenuClassFactory, CNWHoodContextMenu
  12. Author:
  13. Yi-Hsin Sung (yihsins) 25-Oct-1995
  14. --*/
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <shellapi.h>
  20. #include <shlobj.h>
  21. #include <stdio.h>
  22. #define DONT_WANT_SHELLDEBUG
  23. #include <shlobjp.h>
  24. #include <nwreg.h>
  25. #include "nwshcmn.h"
  26. #include "nwshext.h"
  27. //
  28. // Initialize GUIDs (should be done only and at-least once per DLL/EXE)
  29. //
  30. #pragma data_seg(".text")
  31. #define INITGUID
  32. #include <initguid.h>
  33. #include <shlguid.h>
  34. #include "nwclsid.h"
  35. #pragma data_seg()
  36. //
  37. // Global variables
  38. //
  39. LONG g_cRefThisDll = 0; // Reference count of this DLL.
  40. WCHAR g_szProviderName[256]; // Store the provider name
  41. HINSTANCE g_hShellLibrary = NULL;
  42. SHELLGETNETRESOURCE g_pFuncSHGetNetResource = NULL;
  43. SHELLDRAGQUERYFILE g_pFuncSHDragQueryFile = NULL;
  44. SHELLCHANGENOTIFY g_pFuncSHChangeNotify = NULL;
  45. SHELLEXECUTEEX g_pFuncSHExecuteEx = NULL;
  46. #if DBG
  47. WCHAR szDebugStr[256]; // For Debug Output
  48. #endif
  49. BOOL LoadShellDllEntries( VOID );
  50. extern "C"
  51. {
  52. //---------------------------------------------------------------------------
  53. // NwCleanupShellExtension
  54. //---------------------------------------------------------------------------
  55. VOID NwCleanupShellExtensions( VOID )
  56. {
  57. if ( g_hShellLibrary )
  58. {
  59. FreeLibrary( g_hShellLibrary );
  60. g_hShellLibrary = NULL;
  61. }
  62. }
  63. }
  64. //---------------------------------------------------------------------------
  65. // DllCanUnloadNow
  66. //---------------------------------------------------------------------------
  67. STDAPI DllCanUnloadNow(void)
  68. {
  69. #if DBG
  70. wsprintf( szDebugStr,L"In DLLCanUnloadNow: g_cRefThisDll = %d\r\n", g_cRefThisDll);
  71. ODS( szDebugStr );
  72. #endif
  73. return ResultFromScode((g_cRefThisDll == 0) ? S_OK : S_FALSE);
  74. }
  75. //---------------------------------------------------------------------------
  76. // DllGetClassObject
  77. //---------------------------------------------------------------------------
  78. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
  79. {
  80. *ppvOut = NULL;
  81. if ( !LoadShellDllEntries() )
  82. return ResultFromScode(CLASS_E_CLASSNOTAVAILABLE);
  83. if (IsEqualIID(rclsid, CLSID_NetWareObjectExt))
  84. {
  85. CNWObjContextMenuClassFactory *pcf = new CNWObjContextMenuClassFactory;
  86. if ( pcf == NULL )
  87. return ResultFromScode(E_OUTOFMEMORY);
  88. HRESULT hr = pcf->QueryInterface(riid, ppvOut);
  89. if ( FAILED(hr) )
  90. delete pcf;
  91. return hr;
  92. }
  93. else if (IsEqualIID(rclsid, CLSID_NetWareFolderMenuExt))
  94. {
  95. CNWFldContextMenuClassFactory *pcf = new CNWFldContextMenuClassFactory;
  96. if ( pcf == NULL )
  97. return ResultFromScode(E_OUTOFMEMORY);
  98. HRESULT hr = pcf->QueryInterface(riid, ppvOut);
  99. if ( FAILED(hr) )
  100. delete pcf;
  101. return hr;
  102. }
  103. else if (IsEqualIID(rclsid, CLSID_NetworkNeighborhoodMenuExt))
  104. {
  105. CNWHoodContextMenuClassFactory *pcf= new CNWHoodContextMenuClassFactory;
  106. if ( pcf == NULL )
  107. return ResultFromScode(E_OUTOFMEMORY);
  108. HRESULT hr = pcf->QueryInterface(riid, ppvOut);
  109. if ( FAILED(hr) )
  110. delete pcf;
  111. return hr;
  112. }
  113. return ResultFromScode(CLASS_E_CLASSNOTAVAILABLE);
  114. }
  115. BOOL LoadShellDllEntries( VOID )
  116. {
  117. static BOOL s_fLoaded = FALSE;
  118. if ( !s_fLoaded )
  119. {
  120. DWORD err;
  121. HKEY hkey;
  122. g_hShellLibrary = LoadLibrary( L"shell32.dll");
  123. if ( g_hShellLibrary != NULL )
  124. {
  125. s_fLoaded = TRUE;
  126. g_pFuncSHGetNetResource =
  127. (SHELLGETNETRESOURCE) GetProcAddress( g_hShellLibrary,
  128. (LPCSTR)(MAKELONG(SHGetNetResourceORD, 0)) );
  129. g_pFuncSHDragQueryFile =
  130. (SHELLDRAGQUERYFILE) GetProcAddress( g_hShellLibrary,
  131. (LPCSTR) "DragQueryFileW");
  132. g_pFuncSHChangeNotify =
  133. (SHELLCHANGENOTIFY) GetProcAddress( g_hShellLibrary,
  134. (LPCSTR) "SHChangeNotify");
  135. g_pFuncSHExecuteEx =
  136. (SHELLEXECUTEEX) GetProcAddress( g_hShellLibrary,
  137. (LPCSTR) "ShellExecuteExW");
  138. }
  139. // Set the default provider name in case we fail to read
  140. // it from the registry.
  141. wcscpy( g_szProviderName, L"NetWare or Compatible Network");
  142. //
  143. // Read the Network Provider Name.
  144. //
  145. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  146. // \NWCWorkstation\networkprovider
  147. //
  148. err = RegOpenKeyExW(
  149. HKEY_LOCAL_MACHINE,
  150. NW_WORKSTATION_PROVIDER_PATH,
  151. REG_OPTION_NON_VOLATILE, // options
  152. KEY_READ, // desired access
  153. &hkey
  154. );
  155. if ( err == NO_ERROR )
  156. {
  157. LPWSTR pszProviderName = NULL;
  158. //
  159. // ignore the return code. if fail, pszProviderName is NULL
  160. //
  161. err = NwReadRegValue(
  162. hkey,
  163. NW_PROVIDER_VALUENAME,
  164. &pszProviderName // free with LocalFree
  165. );
  166. if ( err == NO_ERROR && pszProviderName != NULL )
  167. {
  168. wcscpy( g_szProviderName, pszProviderName );
  169. LocalFree( pszProviderName );
  170. }
  171. RegCloseKey( hkey );
  172. }
  173. }
  174. return s_fLoaded;
  175. }
  176. //---------------------------------------------------------------------------
  177. // CNWObjContextMenuClassFactory
  178. //---------------------------------------------------------------------------
  179. CNWObjContextMenuClassFactory::CNWObjContextMenuClassFactory()
  180. {
  181. _cRef = 0L;
  182. InterlockedIncrement( &g_cRefThisDll );
  183. #if DBG
  184. wsprintf( szDebugStr,L"CNWObjContextMenuClassFactory::CNWObjContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  185. ODS( szDebugStr );
  186. #endif
  187. }
  188. CNWObjContextMenuClassFactory::~CNWObjContextMenuClassFactory()
  189. {
  190. InterlockedDecrement( &g_cRefThisDll );
  191. #if DBG
  192. wsprintf( szDebugStr,L"CNWObjContextMenuClassFactory::~CNWObjContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  193. ODS( szDebugStr );
  194. #endif
  195. }
  196. STDMETHODIMP CNWObjContextMenuClassFactory::QueryInterface(REFIID riid,
  197. LPVOID FAR *ppv)
  198. {
  199. *ppv = NULL;
  200. // Any interface on this object is the object pointer
  201. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
  202. {
  203. *ppv = (LPCLASSFACTORY)this;
  204. AddRef();
  205. return NOERROR;
  206. }
  207. return ResultFromScode(E_NOINTERFACE);
  208. }
  209. STDMETHODIMP_(ULONG) CNWObjContextMenuClassFactory::AddRef()
  210. {
  211. return ++_cRef;
  212. }
  213. STDMETHODIMP_(ULONG) CNWObjContextMenuClassFactory::Release()
  214. {
  215. if (--_cRef)
  216. return _cRef;
  217. delete this;
  218. return 0L;
  219. }
  220. STDMETHODIMP CNWObjContextMenuClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
  221. REFIID riid,
  222. LPVOID *ppvObj)
  223. {
  224. *ppvObj = NULL;
  225. // Shell extensions typically don't support aggregation (inheritance)
  226. if (pUnkOuter)
  227. return ResultFromScode(CLASS_E_NOAGGREGATION);
  228. // Create the main shell extension object. The shell will then call
  229. // QueryInterface with IID_IShellExtInit--this is how shell extensions are
  230. // initialized.
  231. LPCNWOBJCONTEXTMENU pShellExt = new CNWObjContextMenu(); // Create the CNWObjContextMenu object
  232. if (NULL == pShellExt)
  233. return ResultFromScode(E_OUTOFMEMORY);
  234. //
  235. // We set the reference count of CNWObjContextMenu to one at initialization.
  236. // Hence, we can call Release() after QueryInterface.
  237. // So, if QueryInterface failed, Release will free the object.
  238. //
  239. HRESULT hr = pShellExt->QueryInterface(riid, ppvObj);
  240. pShellExt->Release();
  241. return hr;
  242. }
  243. STDMETHODIMP CNWObjContextMenuClassFactory::LockServer(BOOL fLock)
  244. {
  245. return NOERROR;
  246. }
  247. //---------------------------------------------------------------------------
  248. // CNWObjContextMenu
  249. //---------------------------------------------------------------------------
  250. CNWObjContextMenu::CNWObjContextMenu()
  251. {
  252. _cRef = 1L;
  253. _pDataObj = NULL;
  254. _fGotClusterInfo = FALSE;
  255. _dwTotal = 0;
  256. _dwFree = 0;
  257. InterlockedIncrement( &g_cRefThisDll );
  258. #if DBG
  259. wsprintf( szDebugStr,L"CNWObjContextMenu::CNWObjContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  260. ODS( szDebugStr );
  261. #endif
  262. }
  263. CNWObjContextMenu::~CNWObjContextMenu()
  264. {
  265. if (_pDataObj)
  266. _pDataObj->Release();
  267. InterlockedDecrement( &g_cRefThisDll );
  268. #if DBG
  269. wsprintf( szDebugStr,L"CNWObjContextMenu::~CNWObjContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  270. ODS( szDebugStr );
  271. #endif
  272. }
  273. STDMETHODIMP CNWObjContextMenu::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  274. {
  275. *ppv = NULL;
  276. if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
  277. {
  278. *ppv = (LPSHELLEXTINIT)this;
  279. }
  280. else if (IsEqualIID(riid, IID_IContextMenu))
  281. {
  282. *ppv = (LPCONTEXTMENU)this;
  283. }
  284. else if (IsEqualIID(riid, IID_IShellPropSheetExt))
  285. {
  286. *ppv = (LPSHELLPROPSHEETEXT)this;
  287. }
  288. if (*ppv)
  289. {
  290. AddRef();
  291. return NOERROR;
  292. }
  293. return ResultFromScode(E_NOINTERFACE);
  294. }
  295. STDMETHODIMP_(ULONG) CNWObjContextMenu::AddRef()
  296. {
  297. return ++_cRef;
  298. }
  299. STDMETHODIMP_(ULONG) CNWObjContextMenu::Release()
  300. {
  301. if (--_cRef)
  302. return _cRef;
  303. delete this;
  304. return 0L;
  305. }
  306. //
  307. // FUNCTION: CNWObjContextMenu::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
  308. //
  309. // PURPOSE: Called by the shell when initializing a context menu or property
  310. // sheet extension.
  311. //
  312. // PARAMETERS:
  313. // pIDFolder - Specifies the parent folder
  314. // pDataObj - Spefifies the set of items selected in that folder.
  315. // hRegKey - Specifies the type of the focused item in the selection.
  316. //
  317. // RETURN VALUE:
  318. //
  319. // NOERROR in all cases.
  320. //
  321. // COMMENTS: Note that at the time this function is called, we don't know
  322. // (or care) what type of shell extension is being initialized.
  323. // It could be a context menu or a property sheet.
  324. //
  325. STDMETHODIMP CNWObjContextMenu::Initialize( LPCITEMIDLIST pIDFolder,
  326. LPDATAOBJECT pDataObj,
  327. HKEY hRegKey)
  328. {
  329. // We do not need the registry handle so ignore it.
  330. // Initialize can be called more than once
  331. if (_pDataObj)
  332. _pDataObj->Release();
  333. // Duplicate the object pointer
  334. if (pDataObj)
  335. {
  336. _pDataObj = pDataObj;
  337. pDataObj->AddRef();
  338. }
  339. return NOERROR;
  340. }
  341. //---------------------------------------------------------------------------
  342. // CNWFldContextMenuClassFactory
  343. //---------------------------------------------------------------------------
  344. CNWFldContextMenuClassFactory::CNWFldContextMenuClassFactory()
  345. {
  346. _cRef = 0L;
  347. InterlockedIncrement( &g_cRefThisDll );
  348. #if DBG
  349. wsprintf( szDebugStr,L"CNWFldContextMenuClassFactory::CNWFldContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  350. ODS( szDebugStr );
  351. #endif
  352. }
  353. CNWFldContextMenuClassFactory::~CNWFldContextMenuClassFactory()
  354. {
  355. InterlockedDecrement( &g_cRefThisDll );
  356. #if DBG
  357. wsprintf( szDebugStr,L"CNWFldContextMenuClassFactory::~CNWFldContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  358. ODS( szDebugStr );
  359. #endif
  360. }
  361. STDMETHODIMP CNWFldContextMenuClassFactory::QueryInterface(REFIID riid,
  362. LPVOID FAR *ppv)
  363. {
  364. *ppv = NULL;
  365. // Any interface on this object is the object pointer
  366. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
  367. {
  368. *ppv = (LPCLASSFACTORY)this;
  369. AddRef();
  370. return NOERROR;
  371. }
  372. return ResultFromScode(E_NOINTERFACE);
  373. }
  374. STDMETHODIMP_(ULONG) CNWFldContextMenuClassFactory::AddRef()
  375. {
  376. return ++_cRef;
  377. }
  378. STDMETHODIMP_(ULONG) CNWFldContextMenuClassFactory::Release()
  379. {
  380. if (--_cRef)
  381. return _cRef;
  382. delete this;
  383. return 0L;
  384. }
  385. STDMETHODIMP CNWFldContextMenuClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
  386. REFIID riid,
  387. LPVOID *ppvObj)
  388. {
  389. *ppvObj = NULL;
  390. // Shell extensions typically don't support aggregation (inheritance)
  391. if (pUnkOuter)
  392. return ResultFromScode(CLASS_E_NOAGGREGATION);
  393. // Create the main shell extension object. The shell will then call
  394. // QueryInterface with IID_IShellExtInit--this is how shell extensions are
  395. // initialized.
  396. LPCNWFLDCONTEXTMENU pShellExt = new CNWFldContextMenu(); // Create the CNWFldContextMenu object
  397. if (NULL == pShellExt)
  398. return ResultFromScode(E_OUTOFMEMORY);
  399. //
  400. // We set the reference count of CNWFldContextMenu to one at initialization.
  401. // Hence, we can call Release() after QueryInterface.
  402. // So, if QueryInterface failed, Release will free the object.
  403. //
  404. HRESULT hr = pShellExt->QueryInterface(riid, ppvObj);
  405. pShellExt->Release();
  406. return hr;
  407. }
  408. STDMETHODIMP CNWFldContextMenuClassFactory::LockServer(BOOL fLock)
  409. {
  410. return NOERROR;
  411. }
  412. //---------------------------------------------------------------------------
  413. // CNWFldContextMenu
  414. //---------------------------------------------------------------------------
  415. CNWFldContextMenu::CNWFldContextMenu()
  416. {
  417. _cRef = 1L;
  418. _pDataObj = NULL;
  419. InterlockedIncrement( &g_cRefThisDll );
  420. #if DBG
  421. wsprintf( szDebugStr,L"CNWFldContextMenu::CNWFldContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  422. ODS( szDebugStr );
  423. #endif
  424. }
  425. CNWFldContextMenu::~CNWFldContextMenu()
  426. {
  427. if (_pDataObj)
  428. _pDataObj->Release();
  429. InterlockedDecrement( &g_cRefThisDll );
  430. #if DBG
  431. wsprintf( szDebugStr,L"CNWFldContextMenu::~CNWFldContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  432. ODS( szDebugStr );
  433. #endif
  434. }
  435. STDMETHODIMP CNWFldContextMenu::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  436. {
  437. *ppv = NULL;
  438. if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
  439. {
  440. *ppv = (LPSHELLEXTINIT)this;
  441. }
  442. else if (IsEqualIID(riid, IID_IContextMenu))
  443. {
  444. *ppv = (LPCONTEXTMENU)this;
  445. }
  446. if (*ppv)
  447. {
  448. AddRef();
  449. return NOERROR;
  450. }
  451. return ResultFromScode(E_NOINTERFACE);
  452. }
  453. STDMETHODIMP_(ULONG) CNWFldContextMenu::AddRef()
  454. {
  455. return ++_cRef;
  456. }
  457. STDMETHODIMP_(ULONG) CNWFldContextMenu::Release()
  458. {
  459. if (--_cRef)
  460. return _cRef;
  461. delete this;
  462. return 0L;
  463. }
  464. //
  465. // FUNCTION: CNWFldContextMenu::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
  466. //
  467. // PURPOSE: Called by the shell when initializing a context menu or property
  468. // sheet extension.
  469. //
  470. // PARAMETERS:
  471. // pIDFolder - Specifies the parent folder
  472. // pDataObj - Spefifies the set of items selected in that folder.
  473. // hRegKey - Specifies the type of the focused item in the selection.
  474. //
  475. // RETURN VALUE:
  476. //
  477. // NOERROR in all cases.
  478. //
  479. // COMMENTS: Note that at the time this function is called, we don't know
  480. // (or care) what type of shell extension is being initialized.
  481. // It could be a context menu or a property sheet.
  482. //
  483. STDMETHODIMP CNWFldContextMenu::Initialize( LPCITEMIDLIST pIDFolder,
  484. LPDATAOBJECT pDataObj,
  485. HKEY hRegKey)
  486. {
  487. // We do not need the registry handle so ignore it.
  488. // Initialize can be called more than once
  489. if (_pDataObj)
  490. _pDataObj->Release();
  491. // Duplicate the object pointer
  492. if (pDataObj)
  493. {
  494. _pDataObj = pDataObj;
  495. pDataObj->AddRef();
  496. }
  497. return NOERROR;
  498. }
  499. //---------------------------------------------------------------------------
  500. // CNWHoodContextMenuClassFactory
  501. //---------------------------------------------------------------------------
  502. CNWHoodContextMenuClassFactory::CNWHoodContextMenuClassFactory()
  503. {
  504. _cRef = 0L;
  505. InterlockedIncrement( &g_cRefThisDll );
  506. #if DBG
  507. wsprintf( szDebugStr,L"CNWHoodContextMenuClassFactory::CNWHoodContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  508. ODS( szDebugStr );
  509. #endif
  510. }
  511. CNWHoodContextMenuClassFactory::~CNWHoodContextMenuClassFactory()
  512. {
  513. InterlockedDecrement( &g_cRefThisDll );
  514. #if DBG
  515. wsprintf( szDebugStr,L"CNWHoodContextMenuClassFactory::~CNWHoodContextMenuClassFactory(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  516. ODS( szDebugStr );
  517. #endif
  518. }
  519. STDMETHODIMP CNWHoodContextMenuClassFactory::QueryInterface(REFIID riid,
  520. LPVOID FAR *ppv)
  521. {
  522. *ppv = NULL;
  523. // Any interface on this object is the object pointer
  524. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
  525. {
  526. *ppv = (LPCLASSFACTORY)this;
  527. AddRef();
  528. return NOERROR;
  529. }
  530. return ResultFromScode(E_NOINTERFACE);
  531. }
  532. STDMETHODIMP_(ULONG) CNWHoodContextMenuClassFactory::AddRef()
  533. {
  534. return ++_cRef;
  535. }
  536. STDMETHODIMP_(ULONG) CNWHoodContextMenuClassFactory::Release()
  537. {
  538. if (--_cRef)
  539. return _cRef;
  540. delete this;
  541. return 0L;
  542. }
  543. STDMETHODIMP CNWHoodContextMenuClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
  544. REFIID riid,
  545. LPVOID *ppvObj)
  546. {
  547. *ppvObj = NULL;
  548. // Shell extensions typically don't support aggregation (inheritance)
  549. if (pUnkOuter)
  550. return ResultFromScode(CLASS_E_NOAGGREGATION);
  551. // Create the main shell extension object. The shell will then call
  552. // QueryInterface with IID_IShellExtInit--this is how shell extensions are
  553. // initialized.
  554. LPCNWHOODCONTEXTMENU pShellExt = new CNWHoodContextMenu(); // Create the CNWHoodContextMenu object
  555. if (NULL == pShellExt)
  556. return ResultFromScode(E_OUTOFMEMORY);
  557. //
  558. // We set the reference count of CNWHoodContextMenu to one at initialization.
  559. // Hence, we can call Release() after QueryInterface.
  560. // So, if QueryInterface failed, Release will free the object.
  561. //
  562. HRESULT hr = pShellExt->QueryInterface(riid, ppvObj);
  563. pShellExt->Release();
  564. return hr;
  565. }
  566. STDMETHODIMP CNWHoodContextMenuClassFactory::LockServer(BOOL fLock)
  567. {
  568. return NOERROR;
  569. }
  570. //---------------------------------------------------------------------------
  571. // CNWHoodContextMenu
  572. //---------------------------------------------------------------------------
  573. CNWHoodContextMenu::CNWHoodContextMenu()
  574. {
  575. _cRef = 1L;
  576. _pDataObj = NULL;
  577. InterlockedIncrement( &g_cRefThisDll );
  578. #if DBG
  579. wsprintf( szDebugStr,L"CNWHoodContextMenu::CNWHoodContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  580. ODS( szDebugStr );
  581. #endif
  582. }
  583. CNWHoodContextMenu::~CNWHoodContextMenu()
  584. {
  585. if (_pDataObj)
  586. _pDataObj->Release();
  587. InterlockedDecrement( &g_cRefThisDll );
  588. #if DBG
  589. wsprintf( szDebugStr,L"CNWHoodContextMenu::~CNWHoodContextMenu(), g_cRefThisDll = %d\r\n", g_cRefThisDll);
  590. ODS( szDebugStr );
  591. #endif
  592. }
  593. STDMETHODIMP CNWHoodContextMenu::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  594. {
  595. *ppv = NULL;
  596. if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown))
  597. {
  598. *ppv = (LPSHELLEXTINIT)this;
  599. }
  600. else if (IsEqualIID(riid, IID_IContextMenu))
  601. {
  602. *ppv = (LPCONTEXTMENU)this;
  603. }
  604. if (*ppv)
  605. {
  606. AddRef();
  607. return NOERROR;
  608. }
  609. return ResultFromScode(E_NOINTERFACE);
  610. }
  611. STDMETHODIMP_(ULONG) CNWHoodContextMenu::AddRef()
  612. {
  613. return ++_cRef;
  614. }
  615. STDMETHODIMP_(ULONG) CNWHoodContextMenu::Release()
  616. {
  617. if (--_cRef)
  618. return _cRef;
  619. delete this;
  620. return 0L;
  621. }
  622. //
  623. // FUNCTION: CNWHoodContextMenu::Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY)
  624. //
  625. // PURPOSE: Called by the shell when initializing a context menu or property
  626. // sheet extension.
  627. //
  628. // PARAMETERS:
  629. // pIDFolder - Specifies the parent folder
  630. // pDataObj - Spefifies the set of items selected in that folder.
  631. // hRegKey - Specifies the type of the focused item in the selection.
  632. //
  633. // RETURN VALUE:
  634. //
  635. // NOERROR in all cases.
  636. //
  637. // COMMENTS: Note that at the time this function is called, we don't know
  638. // (or care) what type of shell extension is being initialized.
  639. // It could be a context menu or a property sheet.
  640. //
  641. STDMETHODIMP CNWHoodContextMenu::Initialize( LPCITEMIDLIST pIDFolder,
  642. LPDATAOBJECT pDataObj,
  643. HKEY hRegKey)
  644. {
  645. // We do not need the registry handle so ignore it.
  646. // Initialize can be called more than once
  647. if (_pDataObj)
  648. _pDataObj->Release();
  649. // Duplicate the object pointer
  650. if (pDataObj)
  651. {
  652. _pDataObj = pDataObj;
  653. pDataObj->AddRef();
  654. }
  655. return NOERROR;
  656. }