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.

659 lines
19 KiB

  1. #include "shellprv.h"
  2. #include <sfview.h>
  3. #include "defviewp.h"
  4. int CGenList::Add(LPVOID pv, int nInsert)
  5. {
  6. if (!_hList)
  7. {
  8. _hList = DSA_Create(_cbItem, 8);
  9. if (!_hList)
  10. {
  11. return -1;
  12. }
  13. }
  14. return DSA_InsertItem(_hList, nInsert, pv);
  15. }
  16. int CViewsList::Add(const SFVVIEWSDATA*pView, int nInsert, BOOL bCopy)
  17. {
  18. if (bCopy)
  19. {
  20. pView = CopyData(pView);
  21. if (!pView)
  22. {
  23. return -1;
  24. }
  25. }
  26. int iIndex = CGenList::Add((LPVOID)(&pView), nInsert);
  27. if (bCopy && iIndex<0)
  28. {
  29. SHFree((LPVOID)pView);
  30. }
  31. return iIndex;
  32. }
  33. TCHAR const c_szExtViews[] = TEXT("ExtShellFolderViews");
  34. void CViewsList::AddReg(HKEY hkParent, LPCTSTR pszSubKey)
  35. {
  36. CSHRegKey ckClass(hkParent, pszSubKey);
  37. if (!ckClass)
  38. {
  39. return;
  40. }
  41. CSHRegKey ckShellEx(ckClass, TEXT("shellex"));
  42. if (!ckShellEx)
  43. {
  44. return;
  45. }
  46. CSHRegKey ckViews(ckShellEx, c_szExtViews);
  47. if (!ckViews)
  48. {
  49. return;
  50. }
  51. TCHAR szKey[40];
  52. DWORD dwLen = sizeof(szKey);
  53. SHELLVIEWID vid;
  54. if (ERROR_SUCCESS==SHRegQueryValue(ckViews, NULL, szKey, (LONG*)&dwLen)
  55. && SUCCEEDED(SHCLSIDFromString(szKey, &vid)))
  56. {
  57. _vidDef = vid;
  58. _bGotDef = TRUE;
  59. }
  60. for (int i=0; ; ++i)
  61. {
  62. LONG lRet = RegEnumKey(ckViews, i, szKey, ARRAYSIZE(szKey));
  63. if (lRet == ERROR_MORE_DATA)
  64. {
  65. continue;
  66. }
  67. else if (lRet != ERROR_SUCCESS)
  68. {
  69. // I assume this is ERROR_NO_MORE_ITEMS
  70. break;
  71. }
  72. SFVVIEWSDATA sView;
  73. ZeroMemory(&sView, sizeof(sView));
  74. if (FAILED(SHCLSIDFromString(szKey, &sView.idView)))
  75. {
  76. continue;
  77. }
  78. CSHRegKey ckView(ckViews, szKey);
  79. if (ckView)
  80. {
  81. TCHAR szFile[ARRAYSIZE(sView.wszMoniker)];
  82. DWORD dwType;
  83. // NOTE: This app "Nuts&Bolts" munges the registry and remove the last NULL byte
  84. // from the PersistMoniker string. When we read that string into un-initialized
  85. // local buffer, we do not get a properly null terminated string and we fail to
  86. // create the moniker. So, I zero Init the mem here.
  87. ZeroMemory(szFile, sizeof(szFile));
  88. // Attributes affect all extended views
  89. dwLen = sizeof(sView.dwFlags);
  90. if ((ERROR_SUCCESS != SHQueryValueEx(ckView, TEXT("Attributes"),
  91. NULL, &dwType, &sView.dwFlags, &dwLen))
  92. || dwLen != sizeof(sView.dwFlags)
  93. || !(REG_DWORD==dwType || REG_BINARY==dwType))
  94. {
  95. sView.dwFlags = 0;
  96. }
  97. // We either have a PersistMoniker (docobj) extended view
  98. // or we have an IShellView extended view
  99. //
  100. dwLen = sizeof(szFile);
  101. if (ERROR_SUCCESS == SHQueryValueEx(ckView, TEXT("PersistMoniker"),
  102. NULL, &dwType, szFile, &dwLen) && REG_SZ == dwType)
  103. {
  104. //if the %UserAppData% exists, expand it!
  105. ExpandOtherVariables(szFile, ARRAYSIZE(szFile));
  106. SHTCharToUnicode(szFile, sView.wszMoniker, ARRAYSIZE(sView.wszMoniker));
  107. }
  108. else
  109. {
  110. dwLen = sizeof(szKey);
  111. if (ERROR_SUCCESS == SHQueryValueEx(ckView, TEXT("ISV"),
  112. NULL, &dwType, szKey, &dwLen) && REG_SZ == dwType
  113. && SUCCEEDED(SHCLSIDFromString(szKey, &vid)))
  114. {
  115. sView.idExtShellView = vid;
  116. // Only IShellView extended vies use LParams
  117. dwLen = sizeof(sView.lParam);
  118. if ((ERROR_SUCCESS != SHQueryValueEx(ckView, TEXT("LParam"),
  119. NULL, &dwType, &sView.lParam, &dwLen))
  120. || dwLen != sizeof(sView.lParam)
  121. || !(REG_DWORD==dwType || REG_BINARY==dwType))
  122. {
  123. sView.lParam = 0;
  124. }
  125. }
  126. else
  127. {
  128. if (VID_FolderState != sView.idView)
  129. {
  130. // No moniker, no IShellView extension, this must be a VID_FolderState
  131. // kinda thing. (Otherwise it's a bad desktop.ini.)
  132. //
  133. RIPMSG(0, "Extended view is registered incorrectly.");
  134. continue;
  135. }
  136. }
  137. }
  138. // It has been requested (by OEMs) to allow specifying background
  139. // bitmap and text colors for the regular views. That way they could
  140. // brand the Control Panel page by putting their logo recessed on
  141. // the background. We'd do that here by pulling the stuff out of
  142. // the registry and putting it in the LPCUSTOMVIEWSDATA section...
  143. }
  144. // if docobjextended view that is not webview, DO NOT ADD IT, UNSUPPORTED.
  145. if (!(sView.dwFlags & SFVF_NOWEBVIEWFOLDERCONTENTS)
  146. && !IsEqualGUID(sView.idView, VID_WebView))
  147. continue;
  148. Add(&sView);
  149. }
  150. }
  151. void CViewsList::AddCLSID(CLSID const* pclsid)
  152. {
  153. CSHRegKey ckCLSID(HKEY_CLASSES_ROOT, TEXT("CLSID"));
  154. if (!ckCLSID)
  155. {
  156. return;
  157. }
  158. TCHAR szCLSID[40];
  159. SHStringFromGUID(*pclsid, szCLSID, ARRAYSIZE(szCLSID));
  160. AddReg(ckCLSID, szCLSID);
  161. }
  162. #ifdef DEBUG
  163. //In debug, I want to see if all the realloc code-path works fine!
  164. //So, I deliberately alloc very small amounts.
  165. #define CUSTOM_INITIAL_ALLOC 16
  166. #define CUSTOM_REALLOC_INCREMENT 16
  167. #else
  168. #define CUSTOM_INITIAL_ALLOC 20*64
  169. #define CUSTOM_REALLOC_INCREMENT 512
  170. #endif //DEBUG
  171. //Returns the offset of the string read into the block of memory (in chars)
  172. // NOTE: the index (piCurOffset) and the sizes *piTotalSize, *piSizeRemaining are
  173. // NOTE: in WCHARs, not BYTES
  174. int GetCustomStrData(LPWSTR *pDataBegin, int *piSizeRemaining, int *piTotalSize,
  175. int *piCurOffset, LPCTSTR szSectionName, LPCTSTR szKeyName,
  176. LPCTSTR szIniFile, LPCTSTR lpszPath)
  177. {
  178. TCHAR szStrData[INFOTIPSIZE], szTemp[INFOTIPSIZE];
  179. #ifndef UNICODE
  180. WCHAR wszStrData[MAX_PATH];
  181. #endif
  182. LPWSTR pszStrData;
  183. int iLen, iOffsetBegin = *piCurOffset;
  184. //See if the data is present.
  185. if (!SHGetIniString(szSectionName, szKeyName, szTemp, ARRAYSIZE(szTemp), szIniFile))
  186. {
  187. return -1; //The given data is not present.
  188. }
  189. SHExpandEnvironmentStrings(szTemp, szStrData, ARRAYSIZE(szStrData)); // Expand the env vars if any
  190. //Get the full pathname if required.
  191. if (lpszPath)
  192. PathCombine(szStrData, lpszPath, szStrData);
  193. #ifdef UNICODE
  194. iLen = lstrlen(szStrData);
  195. pszStrData = szStrData;
  196. #else
  197. iLen = MultiByteToWideChar(CP_ACP, 0, szStrData, -1, wszStrData, ARRAYSIZE(wszStrData));
  198. pszStrData = wszStrData;
  199. #endif
  200. iLen++; //Include the NULL character.
  201. while(*piSizeRemaining < iLen)
  202. {
  203. LPWSTR lpNew;
  204. //We need to realloc the block of memory
  205. if (NULL == (lpNew = (LPWSTR)SHRealloc(*pDataBegin, ( *piTotalSize + CUSTOM_REALLOC_INCREMENT) * sizeof(WCHAR))))
  206. return -1; //Unable to realloc; out of mem.
  207. //Note: The begining address of the block could have changed.
  208. *pDataBegin = lpNew;
  209. *piTotalSize += CUSTOM_REALLOC_INCREMENT;
  210. *piSizeRemaining += CUSTOM_REALLOC_INCREMENT;
  211. }
  212. //Add the current directory if required.
  213. StrCpyW((*pDataBegin)+(*piCurOffset), pszStrData);
  214. *piSizeRemaining -= iLen;
  215. *piCurOffset += iLen;
  216. return iOffsetBegin;
  217. }
  218. HRESULT ReadWebViewTemplate(LPCTSTR pszPath, LPTSTR pszWebViewTemplate, int cchWebViewTemplate)
  219. {
  220. SHFOLDERCUSTOMSETTINGS fcs = {sizeof(fcs), FCSM_WEBVIEWTEMPLATE, 0};
  221. fcs.pszWebViewTemplate = pszWebViewTemplate; // template path
  222. fcs.cchWebViewTemplate = cchWebViewTemplate;
  223. return SHGetSetFolderCustomSettings(&fcs, pszPath, FCS_READ);
  224. }
  225. #define ID_EXTVIEWICONAREAIMAGE 3
  226. #define ID_EXTVIEWCOLORSFIRST 4
  227. #define ID_EXTVIEWSTRLAST 5
  228. #define ID_EXTVIEWUICOUNT 6
  229. const LPCTSTR c_szExtViewUIRegKeys[ID_EXTVIEWUICOUNT] =
  230. {
  231. TEXT("MenuName"),
  232. TEXT("HelpText"),
  233. TEXT("TooltipText"),
  234. TEXT("IconArea_Image"),
  235. TEXT("IconArea_TextBackground"),
  236. TEXT("IconArea_Text")
  237. };
  238. void CViewsList::AddIni(LPCTSTR szIniFile, LPCTSTR szPath)
  239. {
  240. TCHAR szViewIDs[12*45]; // Room for about 12 GUIDs including Default=
  241. SHELLVIEWID vid;
  242. //
  243. //First check if the INI file exists before trying to get data from it.
  244. //
  245. if (!PathFileExistsAndAttributes(szIniFile, NULL))
  246. return;
  247. if (GetPrivateProfileString(c_szExtViews, TEXT("Default"), c_szNULL,
  248. szViewIDs, ARRAYSIZE(szViewIDs), szIniFile)
  249. && SUCCEEDED(SHCLSIDFromString(szViewIDs, &vid)))
  250. {
  251. _vidDef = vid;
  252. _bGotDef = TRUE;
  253. }
  254. GetPrivateProfileString(c_szExtViews, NULL, c_szNULL,
  255. szViewIDs, ARRAYSIZE(szViewIDs), szIniFile);
  256. for (LPCTSTR pNextID=szViewIDs; *pNextID; pNextID+=lstrlen(pNextID)+1)
  257. {
  258. SFVVIEWSDATA sViewData;
  259. CUSTOMVIEWSDATA sCustomData;
  260. LPWSTR pszDataBegin = NULL;
  261. int iSizeRemaining = CUSTOM_INITIAL_ALLOC; //Let's begin with 12 strings.
  262. int iTotalSize;
  263. int iCurOffset;
  264. ZeroMemory(&sViewData, sizeof(sViewData));
  265. ZeroMemory(&sCustomData, sizeof(sCustomData));
  266. // there must be a view id
  267. if (FAILED(SHCLSIDFromString(pNextID, &sViewData.idView)))
  268. {
  269. continue;
  270. }
  271. // we blow off IE4b2 customized views. This forces them to run
  272. // the wizard again which will clean this junk up
  273. if (IsEqualIID(sViewData.idView, VID_DefaultCustomWebView))
  274. {
  275. continue;
  276. }
  277. // get the IShellView extended view, if any
  278. BOOL fExtShellView = FALSE;
  279. TCHAR szPreProcName[45];
  280. if (GetPrivateProfileString(c_szExtViews, pNextID, c_szNULL,
  281. szPreProcName, ARRAYSIZE(szPreProcName), szIniFile))
  282. {
  283. fExtShellView = SUCCEEDED(SHCLSIDFromString(szPreProcName, &sViewData.idExtShellView));
  284. }
  285. // All extended views use Attributes
  286. sViewData.dwFlags = GetPrivateProfileInt(pNextID, TEXT("Attributes"), 0, szIniFile) | SFVF_CUSTOMIZEDVIEW;
  287. // For some reason this code uses a much larger buffer
  288. // than seems necessary. I don't know why... [mikesh 29jul97]
  289. TCHAR szViewData[MAX_PATH+MAX_PATH];
  290. szViewData[0] = TEXT('\0'); // For the non-webview case
  291. if (IsEqualGUID(sViewData.idView, VID_WebView) && SUCCEEDED(ReadWebViewTemplate(szPath, szViewData, MAX_PATH)))
  292. {
  293. LPTSTR pszPath = szViewData;
  294. // We want to allow relative paths for the file: protocol
  295. //
  296. if (0 == StrCmpNI(TEXT("file://"), szViewData, 7)) // ARRAYSIZE(TEXT("file://"))
  297. {
  298. pszPath += 7; // ARRAYSIZE(TEXT("file://"))
  299. }
  300. // for webview:// compatibility, keep this working:
  301. else if (0 == StrCmpNI(TEXT("webview://file://"), szViewData, 17)) // ARRAYSIZE(TEXT("file://"))
  302. {
  303. pszPath += 17; // ARRAYSIZE(TEXT("webview://file://"))
  304. }
  305. // handle relative references...
  306. PathCombine(pszPath, szPath, pszPath);
  307. // Avoid overwriting buffers
  308. szViewData[MAX_PATH-1] = NULL;
  309. }
  310. else
  311. {
  312. // only IShellView extensions use LParams
  313. sViewData.lParam = GetPrivateProfileInt( pNextID, TEXT("LParam"), 0, szIniFile );
  314. if (!fExtShellView && VID_FolderState != sViewData.idView)
  315. {
  316. // No moniker, no IShellView extension, this must be a VID_FolderState
  317. // kinda thing. (Otherwise it's a bad desktop.ini.)
  318. //
  319. RIPMSG(0, "Extended view is registered incorrectly.");
  320. continue;
  321. }
  322. }
  323. SHTCharToUnicode(szViewData, sViewData.wszMoniker, ARRAYSIZE(sViewData.wszMoniker));
  324. // NOTE: the size is in WCHARs not in BYTES
  325. pszDataBegin = (LPWSTR)SHAlloc(iSizeRemaining * sizeof(WCHAR));
  326. if (NULL == pszDataBegin)
  327. continue;
  328. iTotalSize = iSizeRemaining;
  329. iCurOffset = 0;
  330. // Read the custom colors
  331. for (int i = 0; i < CRID_COLORCOUNT; i++)
  332. sCustomData.crCustomColors[i] = GetPrivateProfileInt(pNextID, c_szExtViewUIRegKeys[ID_EXTVIEWCOLORSFIRST + i], CLR_MYINVALID, szIniFile);
  333. // Read the extended view strings
  334. for (i = 0; i <= ID_EXTVIEWSTRLAST; i++)
  335. {
  336. sCustomData.acchOffExtViewUIstr[i] = GetCustomStrData(&pszDataBegin,
  337. &iSizeRemaining, &iTotalSize, &iCurOffset,
  338. pNextID, c_szExtViewUIRegKeys[i], szIniFile,
  339. (i == ID_EXTVIEWICONAREAIMAGE ? szPath : NULL));
  340. }
  341. sCustomData.cchSizeOfBlock = (iTotalSize - iSizeRemaining);
  342. sCustomData.lpDataBlock = pszDataBegin;
  343. sViewData.pCustomData = &sCustomData;
  344. // if docobjextended view that is not webview, DO NOT ADD IT, UNSUPPORTED.
  345. if (!(sViewData.dwFlags & SFVF_NOWEBVIEWFOLDERCONTENTS)
  346. && !IsEqualGUID(sViewData.idView, VID_WebView)
  347. && !IsEqualGUID(sViewData.idView, VID_FolderState))
  348. continue;
  349. Add(&sViewData);
  350. //We already copied the data. So, we can free it!
  351. SHFree(pszDataBegin);
  352. }
  353. }
  354. void CViewsList::Empty()
  355. {
  356. _bGotDef = FALSE;
  357. for (int i=GetItemCount()-1; i>=0; --i)
  358. {
  359. SFVVIEWSDATA *sfvData = GetPtr(i);
  360. ASSERT(sfvData);
  361. if (sfvData->dwFlags & SFVF_CUSTOMIZEDVIEW)
  362. {
  363. CUSTOMVIEWSDATA *pCustomPtr = sfvData->pCustomData;
  364. if (pCustomPtr)
  365. {
  366. if (pCustomPtr->lpDataBlock)
  367. SHFree(pCustomPtr->lpDataBlock);
  368. SHFree(pCustomPtr);
  369. }
  370. }
  371. SHFree(sfvData);
  372. }
  373. CGenList::Empty();
  374. }
  375. SFVVIEWSDATA* CViewsList::CopyData(const SFVVIEWSDATA* pData)
  376. {
  377. SFVVIEWSDATA* pCopy = (SFVVIEWSDATA*)SHAlloc(sizeof(SFVVIEWSDATA));
  378. if (pCopy)
  379. {
  380. memcpy(pCopy, pData, sizeof(SFVVIEWSDATA));
  381. if ((pData->dwFlags & SFVF_CUSTOMIZEDVIEW) && pData->pCustomData)
  382. {
  383. CUSTOMVIEWSDATA *pCustomData = (CUSTOMVIEWSDATA *)SHAlloc(sizeof(CUSTOMVIEWSDATA));
  384. if (pCustomData)
  385. {
  386. memcpy(pCustomData, pData->pCustomData, sizeof(CUSTOMVIEWSDATA));
  387. pCopy->pCustomData = pCustomData;
  388. if (pCustomData->lpDataBlock)
  389. {
  390. // NOTE: DataBlock size is in WCHARs
  391. LPWSTR lpDataBlock = (LPWSTR)SHAlloc(pCustomData->cchSizeOfBlock * sizeof(WCHAR));
  392. if (lpDataBlock)
  393. {
  394. // NOTE: DataBlock size is in WCHARs
  395. memcpy(lpDataBlock, pCustomData->lpDataBlock, pCustomData->cchSizeOfBlock * sizeof(WCHAR));
  396. pCustomData->lpDataBlock = lpDataBlock;
  397. }
  398. else
  399. {
  400. SHFree(pCustomData);
  401. goto Failed;
  402. }
  403. }
  404. }
  405. else
  406. {
  407. Failed:
  408. SHFree(pCopy);
  409. pCopy = NULL;
  410. }
  411. }
  412. }
  413. return pCopy;
  414. }
  415. int CViewsList::NextUnique(int nLast)
  416. {
  417. for (int nNext = nLast + 1; ; ++nNext)
  418. {
  419. SFVVIEWSDATA* pItem = GetPtr(nNext);
  420. if (!pItem)
  421. {
  422. break;
  423. }
  424. for (int nPrev=nNext-1; nPrev>=0; --nPrev)
  425. {
  426. SFVVIEWSDATA*pPrev = GetPtr(nPrev);
  427. if (pItem->idView == pPrev->idView)
  428. {
  429. break;
  430. }
  431. }
  432. if (nPrev < 0)
  433. {
  434. return nNext;
  435. }
  436. }
  437. return -1;
  438. }
  439. // Note this is 1-based
  440. int CViewsList::NthUnique(int nUnique)
  441. {
  442. for (int nNext = -1; nUnique > 0; --nUnique)
  443. {
  444. nNext = NextUnique(nNext);
  445. if (nNext < 0)
  446. {
  447. return -1;
  448. }
  449. }
  450. return nNext;
  451. }
  452. void CCallback::_GetExtViews(BOOL bForce)
  453. {
  454. CDefView* pView = IToClass(CDefView, _cCallback, this);
  455. IEnumSFVViews *pev = NULL;
  456. if (bForce)
  457. {
  458. _bGotViews = FALSE;
  459. }
  460. if (_bGotViews)
  461. {
  462. return;
  463. }
  464. _lViews.Empty();
  465. SHELLVIEWID vid = VID_LargeIcons;
  466. if (FAILED(pView->CallCB(SFVM_GETVIEWS, (WPARAM)&vid, (LPARAM)&pev)) ||
  467. !pev)
  468. {
  469. return;
  470. }
  471. _lViews.SetDef(&vid);
  472. SFVVIEWSDATA *pData;
  473. ULONG uFetched;
  474. while ((pev->Next(1, &pData, &uFetched) == S_OK) && (uFetched == 1))
  475. {
  476. // The list comes to us in general to specific order, but we want
  477. // to search it in specific->general order. Inverting the list
  478. // is easiest here, even though it causes a bunch of memcpy calls.
  479. //
  480. _lViews.Prepend(pData, FALSE);
  481. }
  482. ATOMICRELEASE(pev);
  483. _bGotViews = TRUE;
  484. }
  485. HRESULT CCallback::TryLegacyGetViews(SFVM_WEBVIEW_TEMPLATE_DATA* pvit)
  486. {
  487. CDefView* pView = IToClass(CDefView, _cCallback, this);
  488. HRESULT hr = E_FAIL;
  489. CLSID clsid;
  490. HRESULT hr2 = IUnknown_GetClassID(pView->_pshf, &clsid);
  491. if (FAILED(hr2) || !(SHGetObjectCompatFlags(NULL, &clsid) & OBJCOMPATF_NOLEGACYWEBVIEW))
  492. {
  493. _GetExtViews(FALSE);
  494. if (_bGotViews)
  495. {
  496. SFVVIEWSDATA* pItem;
  497. GetViewIdFromGUID(&VID_WebView, &pItem);
  498. if (pItem)
  499. {
  500. StrCpyNW(pvit->szWebView, pItem->wszMoniker, ARRAYSIZE(pvit->szWebView));
  501. hr = S_OK;
  502. }
  503. }
  504. else if (SUCCEEDED(hr2))
  505. {
  506. // check for PersistMoniker under isf's coclass (Web Folders used this in W2K to get .htt Web View)
  507. WCHAR szCLSID[GUIDSTR_MAX];
  508. SHStringFromGUID(clsid, szCLSID, ARRAYSIZE(szCLSID));
  509. WCHAR szkey[MAX_PATH];
  510. wnsprintf(szkey, ARRAYSIZE(szkey), L"CLSID\\%s\\shellex\\ExtShellFolderViews\\{5984FFE0-28D4-11CF-AE66-08002B2E1262}", szCLSID);
  511. DWORD cbSize = sizeof(pvit->szWebView);
  512. if (ERROR_SUCCESS == SHGetValueW(HKEY_CLASSES_ROOT, szkey, L"PersistMoniker", NULL, pvit->szWebView, &cbSize))
  513. {
  514. hr = S_OK;
  515. }
  516. }
  517. }
  518. return hr;
  519. }
  520. HRESULT CCallback::OnRefreshLegacy(void* pv, BOOL fPrePost)
  521. {
  522. // If we're using the SFVM_GETVIEWS layer, invalidate it
  523. if (_bGotViews)
  524. {
  525. _lViews.Empty();
  526. _bGotViews = FALSE;
  527. }
  528. return S_OK;
  529. }
  530. int CCallback::GetViewIdFromGUID(SHELLVIEWID const *pvid, SFVVIEWSDATA** ppItem)
  531. {
  532. int iView = -1;
  533. for (UINT uView=0; uView<MAX_EXT_VIEWS; ++uView)
  534. {
  535. iView = _lViews.NextUnique(iView);
  536. SFVVIEWSDATA* pItem = _lViews.GetPtr(iView);
  537. if (!pItem)
  538. {
  539. break;
  540. }
  541. if (*pvid == pItem->idView)
  542. {
  543. if (ppItem)
  544. *ppItem = pItem;
  545. return (int)uView;
  546. }
  547. }
  548. if (ppItem)
  549. *ppItem = NULL;
  550. return -1;
  551. }