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.

629 lines
19 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "shellids.h" // new help ids are stored here
  4. #include "findfilter.h"
  5. #include "netview.h"
  6. #include "prop.h"
  7. #include "ids.h"
  8. STDAPI CNetwork_EnumSearches(IShellFolder2 *psf2, IEnumExtraSearch **ppenum);
  9. class CNetFindEnum;
  10. class CNetFindFilter : public IFindFilter
  11. {
  12. friend CNetFindEnum;
  13. public:
  14. CNetFindFilter();
  15. // IUnknown
  16. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  17. STDMETHODIMP_(ULONG) AddRef();
  18. STDMETHODIMP_(ULONG) Release();
  19. // IFindFilter
  20. STDMETHODIMP GetStatusMessageIndex(UINT uContext, UINT *puMsgIndex);
  21. STDMETHODIMP GetFolderMergeMenuIndex(UINT *puBGMainMergeMenu, UINT *puBGPopupMergeMenu);
  22. STDMETHODIMP FFilterChanged();
  23. STDMETHODIMP GenerateTitle(LPTSTR *ppszTile, BOOL fFileName);
  24. STDMETHODIMP PrepareToEnumObjects(HWND hwnd, DWORD * pdwFlags);
  25. STDMETHODIMP ClearSearchCriteria();
  26. STDMETHODIMP EnumObjects(IShellFolder *psf, LPCITEMIDLIST pidlStart, DWORD grfFlags, int iColSort,
  27. LPTSTR pszProgressText, IRowsetWatchNotify *prwn, IFindEnum **ppfindenum);
  28. STDMETHODIMP GetColumnsFolder(IShellFolder2 **ppsf);
  29. STDMETHODIMP_(BOOL) MatchFilter(IShellFolder *psf, LPCITEMIDLIST pidl);
  30. STDMETHODIMP SaveCriteria(IStream * pstm, WORD fCharType);
  31. STDMETHODIMP RestoreCriteria(IStream * pstm, int cCriteria, WORD fCharType);
  32. STDMETHODIMP DeclareFSNotifyInterest(HWND hwndDlg, UINT uMsg);
  33. STDMETHODIMP GetColSaveStream(WPARAM wParam, IStream **ppstm);
  34. STDMETHODIMP GenerateQueryRestrictions(LPWSTR *ppwszQuery, DWORD *pdwGQRFlags);
  35. STDMETHODIMP ReleaseQuery();
  36. STDMETHODIMP UpdateField(LPCWSTR pszField, VARIANT vValue);
  37. STDMETHODIMP ResetFieldsToDefaults();
  38. STDMETHODIMP GetItemContextMenu(HWND hwndOwner, IFindFolder* pff, IContextMenu** ppcm);
  39. STDMETHODIMP GetDefaultSearchGUID(IShellFolder2 *psf2, LPGUID lpGuid);
  40. STDMETHODIMP EnumSearches(IShellFolder2 *psf2, LPENUMEXTRASEARCH *ppenum);
  41. STDMETHODIMP GetSearchFolderClassId(LPGUID lpGuid);
  42. STDMETHODIMP GetNextConstraint(VARIANT_BOOL fReset, BSTR *pName, VARIANT *pValue, VARIANT_BOOL *pfFound);
  43. STDMETHODIMP GetQueryLanguageDialect(ULONG * pulDialect);
  44. STDMETHODIMP GetWarningFlags(DWORD *pdwWarningFlags) { return E_NOTIMPL; }
  45. protected:
  46. LPTSTR _pszCompName; // the one we do compares with
  47. TCHAR _szUserInputCompName[MAX_PATH]; // User input
  48. private:
  49. ~CNetFindFilter();
  50. LONG _cRef;
  51. LPITEMIDLIST _pidlStart; // Where to start the search from.
  52. // Data associated with the file name.
  53. };
  54. CNetFindFilter::CNetFindFilter() : _cRef(1)
  55. {
  56. }
  57. CNetFindFilter::~CNetFindFilter()
  58. {
  59. ILFree(_pidlStart);
  60. Str_SetPtr(&_pszCompName, NULL);
  61. }
  62. STDMETHODIMP CNetFindFilter::QueryInterface(REFIID riid, void **ppv)
  63. {
  64. static const QITAB qit[] = {
  65. QITABENT(CNetFindFilter, IFindFilter),
  66. { 0 },
  67. };
  68. return QISearch(this, qit, riid, ppv);
  69. }
  70. STDMETHODIMP_(ULONG) CNetFindFilter::AddRef()
  71. {
  72. return InterlockedIncrement(&_cRef);
  73. }
  74. STDMETHODIMP_(ULONG) CNetFindFilter::Release()
  75. {
  76. if (InterlockedDecrement(&_cRef))
  77. return _cRef;
  78. delete this;
  79. return 0;
  80. }
  81. STDMETHODIMP CNetFindFilter::GetStatusMessageIndex(UINT uContext, UINT *puMsgIndex)
  82. {
  83. // Currently context is not used
  84. *puMsgIndex = IDS_COMPUTERSFOUND;
  85. return S_OK;
  86. }
  87. STDMETHODIMP CNetFindFilter::GetFolderMergeMenuIndex(UINT *puBGMainMergeMenu, UINT *puBGPopupMergeMenu)
  88. {
  89. *puBGPopupMergeMenu = 0;
  90. return S_OK;
  91. }
  92. STDMETHODIMP CNetFindFilter::GetItemContextMenu(HWND hwndOwner, IFindFolder* pff, IContextMenu **ppcm)
  93. {
  94. return CFindItem_Create(hwndOwner, pff, ppcm);
  95. }
  96. STDMETHODIMP CNetFindFilter::GetDefaultSearchGUID(IShellFolder2 *psf2, GUID *pGuid)
  97. {
  98. *pGuid = SRCID_SFindComputer;
  99. return S_OK;
  100. }
  101. STDMETHODIMP CNetFindFilter::EnumSearches(IShellFolder2 *psf2, IEnumExtraSearch **ppenum)
  102. {
  103. return CNetwork_EnumSearches(psf2, ppenum);
  104. }
  105. STDMETHODIMP CNetFindFilter::GetSearchFolderClassId(LPGUID lpGuid)
  106. {
  107. *lpGuid = CLSID_ComputerFindFolder;
  108. return S_OK;
  109. }
  110. STDMETHODIMP CNetFindFilter::GetNextConstraint(VARIANT_BOOL fReset, BSTR *pName, VARIANT *pValue, VARIANT_BOOL *pfFound)
  111. {
  112. *pName = NULL;
  113. *pfFound = FALSE;
  114. VariantClear(pValue);
  115. return E_NOTIMPL;
  116. }
  117. STDMETHODIMP CNetFindFilter::GetQueryLanguageDialect(ULONG * pulDialect)
  118. {
  119. if (pulDialect)
  120. *pulDialect = 0;
  121. return E_NOTIMPL;
  122. }
  123. STDMETHODIMP CNetFindFilter::FFilterChanged()
  124. {
  125. // Currently not saving so who cares?
  126. return S_FALSE;
  127. }
  128. STDMETHODIMP CNetFindFilter::GenerateTitle(LPTSTR *ppszTitle, BOOL fFileName)
  129. {
  130. // Now lets construct the message from the resource
  131. *ppszTitle = ShellConstructMessageString(HINST_THISDLL,
  132. MAKEINTRESOURCE(IDS_FIND_TITLE_COMPUTER), fFileName ? TEXT(" #") : TEXT(":"));
  133. return *ppszTitle ? S_OK : E_OUTOFMEMORY;
  134. }
  135. STDMETHODIMP CNetFindFilter::ClearSearchCriteria()
  136. {
  137. return S_OK;
  138. }
  139. STDAPI CreateDefaultComputerFindFilter(IFindFilter **ppff)
  140. {
  141. *ppff = new CNetFindFilter;
  142. return *ppff ? S_OK : E_OUTOFMEMORY;
  143. }
  144. class CNetFindEnum : public IFindEnum
  145. {
  146. public:
  147. CNetFindEnum(CNetFindFilter *pnff, IShellFolder *psf, LPTSTR pszDisplayText, DWORD grfFlags, LPITEMIDLIST pidlStart);
  148. // IUnknown
  149. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  150. STDMETHODIMP_(ULONG) AddRef();
  151. STDMETHODIMP_(ULONG) Release();
  152. // IFindEnum
  153. STDMETHODIMP Next(LPITEMIDLIST *ppidl, int *pcObjectSearched, int *pcFoldersSearched, BOOL *pfContinue, int *pState);
  154. STDMETHODIMP Skip(int celt) { return E_NOTIMPL; }
  155. STDMETHODIMP Reset() { return E_NOTIMPL; }
  156. STDMETHODIMP StopSearch() { return E_NOTIMPL; }
  157. STDMETHODIMP_(BOOL) FQueryIsAsync();
  158. STDMETHODIMP GetAsyncCount(DBCOUNTITEM *pdwTotalAsync, int *pnPercentComplete, BOOL *pfQueryDone);
  159. STDMETHODIMP GetItemIDList(UINT iItem, LPITEMIDLIST *ppidl);
  160. STDMETHODIMP GetItemID(UINT iItem, DWORD *puWorkID);
  161. STDMETHODIMP SortOnColumn(UINT iCol, BOOL fAscending);
  162. private:
  163. ~CNetFindEnum();
  164. HRESULT _FindCompByUNCName(LPITEMIDLIST *ppidl, int *piState);
  165. LONG _cRef;
  166. IFindFolder *_pff; // find folder
  167. // Stuff to use in the search
  168. DWORD _grfFlags; // Flags that control things like recursion
  169. // filter info...
  170. LPTSTR _pszDisplayText; // Place to write feadback text into
  171. CNetFindFilter *_pnetf; // Pointer to the net filter...
  172. // enumeration state
  173. IShellFolder *_psfEnum; // Pointer to shell folder for the object.
  174. IEnumIDList *_penum; // Enumerator in use.
  175. LPITEMIDLIST _pidlFolder; // The idlist of the currently processing
  176. LPITEMIDLIST _pidlStart; // Pointer to the starting point.
  177. int _iFolder; // Which folder are we adding items for?
  178. BOOL _fFindUNC; // Find UNC special case
  179. int _iPassCnt; // Used to control when to reiterat...
  180. };
  181. CNetFindEnum::CNetFindEnum(CNetFindFilter *pnff, IShellFolder *psf, LPTSTR pszDisplayText, DWORD grfFlags, LPITEMIDLIST pidlStart) :
  182. _cRef(1), _pnetf(pnff), _pszDisplayText(pszDisplayText), _grfFlags(grfFlags), _iFolder(-1)
  183. {
  184. ASSERT(0 == _iPassCnt);
  185. _pnetf->AddRef();
  186. psf->QueryInterface(IID_PPV_ARG(IFindFolder, &_pff));
  187. ASSERT(_pff);
  188. if (pidlStart)
  189. SHILClone(pidlStart, &_pidlStart);
  190. else
  191. SHGetDomainWorkgroupIDList(&_pidlStart);
  192. // special case to force us to search for specific UNC
  193. _fFindUNC = _pnetf->_pszCompName && (_pnetf->_pszCompName[0] == TEXT('\\'));
  194. }
  195. CNetFindEnum::~CNetFindEnum()
  196. {
  197. // Release any open enumerator and open IShell folder we may have.
  198. if (_psfEnum)
  199. _psfEnum->Release();
  200. if (_penum)
  201. _penum->Release();
  202. _pff->Release();
  203. _pnetf->Release();
  204. ILFree(_pidlStart);
  205. ILFree(_pidlFolder);
  206. }
  207. STDMETHODIMP CNetFindEnum::QueryInterface(REFIID riid, void **ppv)
  208. {
  209. static const QITAB qit[] = {
  210. // QITABENT(CNetFindEnum, IFindEnum),
  211. { 0 },
  212. };
  213. return QISearch(this, qit, riid, ppv);
  214. }
  215. STDMETHODIMP_(ULONG) CNetFindEnum::AddRef()
  216. {
  217. return InterlockedIncrement(&_cRef);
  218. }
  219. STDMETHODIMP_(ULONG) CNetFindEnum::Release()
  220. {
  221. if (InterlockedDecrement(&_cRef))
  222. return _cRef;
  223. delete this;
  224. return 0;
  225. }
  226. STDMETHODIMP CNetFindFilter::EnumObjects(IShellFolder *psf, LPCITEMIDLIST pidlStart,
  227. DWORD grfFlags, int iColSort, LPTSTR pszDisplayText,
  228. IRowsetWatchNotify *prsn, IFindEnum **ppfindenum)
  229. {
  230. // We need to construct the iterator
  231. *ppfindenum = new CNetFindEnum(this, psf, pszDisplayText, grfFlags, _pidlStart);
  232. return *ppfindenum ? S_OK : E_OUTOFMEMORY;
  233. }
  234. STDMETHODIMP CNetFindFilter::PrepareToEnumObjects(HWND hwnd, DWORD *pdwFlags)
  235. {
  236. *pdwFlags = 0;
  237. // Also lets convert the Computer name pattern into the strings
  238. // will do the compares against.
  239. if ((_szUserInputCompName[0] == TEXT('\\')) &&
  240. (_szUserInputCompName[1] == TEXT('\\')))
  241. {
  242. Str_SetPtr(&_pszCompName, _szUserInputCompName);
  243. }
  244. else
  245. {
  246. SetupWildCardingOnFileSpec(_szUserInputCompName, &_pszCompName);
  247. }
  248. return S_OK;
  249. }
  250. STDMETHODIMP CNetFindFilter::GetColumnsFolder(IShellFolder2 **ppsf)
  251. {
  252. LPITEMIDLIST pidl;
  253. HRESULT hr = SHGetDomainWorkgroupIDList(&pidl);
  254. if (SUCCEEDED(hr))
  255. {
  256. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder2, pidl, ppsf));
  257. ILFree(pidl);
  258. }
  259. else
  260. *ppsf = NULL;
  261. return hr;
  262. }
  263. STDMETHODIMP_(BOOL) CNetFindFilter::MatchFilter(IShellFolder *psf, LPCITEMIDLIST pidl)
  264. {
  265. if (this->_pszCompName && this->_pszCompName[0])
  266. {
  267. // Although for now not much...
  268. TCHAR szPath[MAX_PATH];
  269. return SUCCEEDED(DisplayNameOf(psf, pidl, SHGDN_NORMAL, szPath, ARRAYSIZE(szPath))) &&
  270. PathMatchSpec(szPath, _pszCompName);
  271. }
  272. return TRUE; // emtpy search, return TRUE (yes)
  273. }
  274. STDMETHODIMP CNetFindFilter::SaveCriteria(IStream *pstm, WORD fCharType)
  275. {
  276. return S_OK;
  277. }
  278. STDMETHODIMP CNetFindFilter::RestoreCriteria(IStream *pstm, int cCriteria, WORD fCharType)
  279. {
  280. return S_OK;
  281. }
  282. STDMETHODIMP CNetFindFilter::GetColSaveStream(WPARAM wparam, IStream **ppstm)
  283. {
  284. *ppstm = NULL;
  285. return E_NOTIMPL;
  286. }
  287. STDMETHODIMP CNetFindFilter::GenerateQueryRestrictions(LPWSTR *ppszQuery, DWORD *pdwFlags)
  288. {
  289. if (ppszQuery)
  290. *ppszQuery = NULL;
  291. *pdwFlags = 0;
  292. return E_NOTIMPL;
  293. }
  294. STDMETHODIMP CNetFindFilter::ReleaseQuery()
  295. {
  296. return S_OK;
  297. }
  298. HRESULT CNetFindFilter::UpdateField(LPCWSTR pszField, VARIANT vValue)
  299. {
  300. HRESULT hr = E_FAIL;
  301. if (0 == StrCmpIW(pszField, L"LookIn"))
  302. {
  303. hr = S_OK; // ignored
  304. }
  305. else if (0 == StrCmpIW(pszField, L"SearchFor"))
  306. {
  307. // Careful! VariantToStr returns a pointer, not an HRESULT
  308. if (VariantToStr(&vValue, _szUserInputCompName, ARRAYSIZE(_szUserInputCompName)))
  309. {
  310. hr = S_OK;
  311. }
  312. }
  313. return hr;
  314. }
  315. HRESULT CNetFindFilter::ResetFieldsToDefaults()
  316. {
  317. _szUserInputCompName[0] = 0;
  318. return S_OK;
  319. }
  320. STDMETHODIMP CNetFindFilter::DeclareFSNotifyInterest(HWND hwndDlg, UINT uMsg)
  321. {
  322. SHChangeNotifyEntry fsne;
  323. fsne.fRecursive = TRUE;
  324. fsne.pidl = _pidlStart;
  325. if (fsne.pidl)
  326. {
  327. SHChangeNotifyRegister(hwndDlg, SHCNRF_NewDelivery | SHCNRF_ShellLevel, SHCNE_DISKEVENTS, uMsg, 1, &fsne);
  328. }
  329. return S_OK;
  330. }
  331. // chop off all of an UNC path except the \\server portion
  332. void _StripToServer(LPTSTR pszUNC)
  333. {
  334. for (pszUNC += 2; *pszUNC; pszUNC = CharNext(pszUNC))
  335. {
  336. if (*pszUNC == TEXT('\\'))
  337. {
  338. // found something after server name, so get rid of it
  339. *pszUNC = 0;
  340. break;
  341. }
  342. }
  343. }
  344. // Helper function to the next function to help process find computer
  345. // on returning computers by UNC names...
  346. HRESULT CNetFindEnum::_FindCompByUNCName(LPITEMIDLIST *ppidl, int *piState)
  347. {
  348. *piState = GNF_DONE; // assume we are done
  349. // Two cases, There is a UNC name entered. If so we need to process
  350. // this by extracting everythign off after the server name...
  351. if (_pnetf->_pszCompName && _pnetf->_pszCompName[0])
  352. {
  353. if (PathIsUNC(_pnetf->_pszCompName))
  354. {
  355. _StripToServer(_pnetf->_pszCompName);
  356. }
  357. else
  358. {
  359. // no unc name, but lets try to convert to unc name
  360. TCHAR szTemp[MAX_PATH];
  361. szTemp[0] = TEXT('\\');
  362. szTemp[1] = TEXT('\\');
  363. szTemp[2] = 0;
  364. StrCatBuff(szTemp, _pnetf->_szUserInputCompName, ARRAYSIZE(szTemp));
  365. _StripToServer(szTemp);
  366. Str_SetPtr(&_pnetf->_pszCompName, szTemp);
  367. }
  368. }
  369. if (_pnetf->_pszCompName && _pnetf->_pszCompName[0])
  370. {
  371. // see if we can parse this guy... if so we have a match
  372. LPITEMIDLIST pidl;
  373. if (SUCCEEDED(SHParseDisplayName(_pnetf->_pszCompName, NULL, &pidl, 0, NULL)))
  374. {
  375. LPITEMIDLIST pidlFolder;
  376. LPCITEMIDLIST pidlChild;
  377. if (SUCCEEDED(SplitIDList(pidl, &pidlFolder, &pidlChild)))
  378. {
  379. if (SUCCEEDED(_pff->AddFolder(pidlFolder, FALSE, &_iFolder)))
  380. {
  381. if (SUCCEEDED(_pff->AddDataToIDList(pidlChild, _iFolder, pidlFolder, DFDF_NONE, 0, 0, 0, ppidl)))
  382. *piState = GNF_MATCH;
  383. }
  384. ILFree(pidlFolder);
  385. }
  386. ILFree(pidl);
  387. }
  388. }
  389. return S_OK;
  390. }
  391. STDMETHODIMP CNetFindEnum::Next(LPITEMIDLIST *ppidl, int *pcObjectSearched,
  392. int *pcFoldersSearched, BOOL *pfContinue, int *piState)
  393. {
  394. HRESULT hr;
  395. // Special case to find UNC Names quickly
  396. if (_fFindUNC)
  397. {
  398. // If not the first time through return that we are done!
  399. if (_iPassCnt)
  400. {
  401. *piState = GNF_DONE;
  402. return S_OK;
  403. }
  404. _iPassCnt = 1;
  405. hr = _FindCompByUNCName(ppidl, piState);
  406. }
  407. else
  408. {
  409. BOOL fContinue = TRUE;
  410. do
  411. {
  412. if (_penum)
  413. {
  414. LPITEMIDLIST pidl;
  415. if (S_OK == _penum->Next(1, &pidl, NULL))
  416. {
  417. // Now see if this is someone we might want to return.
  418. // Our Match function take esither find data or idlist...
  419. // for networks we work off of the idlist,
  420. fContinue = FALSE; // We can exit the loop;
  421. (*pcObjectSearched)++;
  422. if (_pnetf->MatchFilter(_psfEnum, pidl))
  423. {
  424. *piState = GNF_MATCH;
  425. // see if we have to add this folder to our list.
  426. if (-1 == _iFolder)
  427. _pff->AddFolder(_pidlFolder, FALSE, &_iFolder);
  428. if (SUCCEEDED(_pff->AddDataToIDList(pidl, _iFolder, _pidlFolder, DFDF_NONE, 0, 0, 0, ppidl)))
  429. {
  430. if ((_iPassCnt == 1) && _pnetf->_pszCompName && _pnetf->_pszCompName[0])
  431. {
  432. // See if this is an exact match of the name
  433. // we are looking for. If it is we set pass=2
  434. // as to not add the item twice.
  435. TCHAR szName[MAX_PATH];
  436. if (SUCCEEDED(DisplayNameOf(_psfEnum, pidl, SHGDN_NORMAL, szName, ARRAYSIZE(szName))) &&
  437. (0 == lstrcmpi(szName, _pnetf->_szUserInputCompName)))
  438. {
  439. _iPassCnt = 2;
  440. }
  441. }
  442. ILFree(pidl);
  443. pidl = NULL;
  444. break;
  445. }
  446. }
  447. else
  448. {
  449. *piState = GNF_NOMATCH;
  450. }
  451. ILFree(pidl);
  452. }
  453. else
  454. {
  455. ATOMICRELEASE(_penum); // release and zero
  456. ATOMICRELEASE(_psfEnum);
  457. }
  458. }
  459. if (!_penum)
  460. {
  461. switch (_iPassCnt)
  462. {
  463. case 1:
  464. // We went through all of the items see if there is
  465. // an exact match...
  466. _iPassCnt = 2;
  467. return _FindCompByUNCName(ppidl, piState);
  468. case 2:
  469. // We looped through everything so return done!
  470. *piState = GNF_DONE;
  471. return S_OK;
  472. case 0:
  473. // This is the main pass through here...
  474. // Need to clone the idlist
  475. hr = SHILClone(_pidlStart, &_pidlFolder);
  476. if (SUCCEEDED(hr))
  477. {
  478. _iPassCnt = 1;
  479. // We will do the first on in our own thread.
  480. if (SUCCEEDED(SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, _pidlFolder, &_psfEnum))))
  481. {
  482. if (S_OK != _psfEnum->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &_penum))
  483. {
  484. // Failed to get iterator so release folder.
  485. ATOMICRELEASE(_psfEnum);
  486. ASSERT(NULL == _penum);
  487. }
  488. }
  489. break;
  490. }
  491. else
  492. {
  493. *piState = GNF_ERROR;
  494. return hr;
  495. }
  496. }
  497. (*pcFoldersSearched)++;
  498. // update progress text
  499. SHGetNameAndFlags(_pidlFolder, SHGDN_NORMAL, _pszDisplayText, MAX_PATH, NULL);
  500. }
  501. } while (fContinue && *pfContinue);
  502. hr = S_OK;
  503. }
  504. return hr;
  505. }
  506. STDMETHODIMP_(BOOL) CNetFindEnum::FQueryIsAsync()
  507. {
  508. return FALSE;
  509. }
  510. STDMETHODIMP CNetFindEnum::GetAsyncCount(DBCOUNTITEM *pdwTotalAsync, int *pnPercentComplete, BOOL *pfQueryDone)
  511. {
  512. return E_NOTIMPL;
  513. }
  514. STDMETHODIMP CNetFindEnum::GetItemIDList(UINT iItem, LPITEMIDLIST *ppidl)
  515. {
  516. return E_NOTIMPL;
  517. }
  518. STDMETHODIMP CNetFindEnum::GetItemID(UINT iItem, DWORD *puWorkID)
  519. {
  520. *puWorkID = (UINT)-1;
  521. return E_NOTIMPL;
  522. }
  523. STDMETHODIMP CNetFindEnum::SortOnColumn(UINT iCOl, BOOL fAscending)
  524. {
  525. return E_NOTIMPL;
  526. }