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.

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