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.

649 lines
21 KiB

  1. /////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1997 Active Voice Corporation. All Rights Reserved.
  4. //
  5. // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
  6. //
  7. // Other brand and product names used herein are trademarks of their respective owners.
  8. //
  9. // The entire program and user interface including the structure, sequence, selection,
  10. // and arrangement of the dialog, the exclusively "yes" and "no" choices represented
  11. // by "1" and "2," and each dialog message are protected by copyrights registered in
  12. // the United States and by international treaties.
  13. //
  14. // Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
  15. // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
  16. //
  17. // Active Voice Corporation
  18. // Seattle, Washington
  19. // USA
  20. //
  21. /////////////////////////////////////////////////////////////////////////////////////////
  22. // ConfExplorerDetailsView.cpp : Implementation of CConfExplorerDetailsView
  23. #include "stdafx.h"
  24. #include <stdio.h>
  25. #include "TapiDialer.h"
  26. #include "avTapi.h"
  27. #include "CEDetailsVw.h"
  28. #include "CETreeView.h"
  29. #include "ConfExp.h"
  30. #include "SDPBlb.h"
  31. static UINT arCols[] = { IDS_EXPLORE_COLUMN_NAME,
  32. IDS_EXPLORE_COLUMN_PURPOSE,
  33. IDS_EXPLORE_COLUMN_STARTS,
  34. IDS_EXPLORE_COLUMN_ENDS,
  35. IDS_EXPLORE_COLUMN_ORIGINATOR };
  36. // Sort function
  37. static int CALLBACK CompareFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
  38. {
  39. CConfExplorerDetailsView *p = (CConfExplorerDetailsView *) lParamSort;
  40. return ((CConfDetails *) lParam1)->Compare( (CConfDetails *) lParam2, p->IsSortAscending(), p->GetSortColumn(), p->GetSecondarySortColumn() );
  41. }
  42. /////////////////////////////////////////////////////////////////////////////
  43. // CConfExplorerDetailsView
  44. CConfExplorerDetailsView::CConfExplorerDetailsView()
  45. {
  46. m_pIConfExplorer = NULL;
  47. m_nSortColumn = 0;
  48. m_bSortAscending = true;
  49. m_nUpdateCount = 0;
  50. }
  51. void CConfExplorerDetailsView::FinalRelease()
  52. {
  53. ATLTRACE(_T(".enter.CConfExplorerDetailsView::FinalRelease().\n"));
  54. DeleteAllItems();
  55. put_hWnd( NULL );
  56. put_ConfExplorer( NULL );
  57. CComObjectRootEx<CComMultiThreadModel>::FinalRelease();
  58. }
  59. STDMETHODIMP CConfExplorerDetailsView::get_hWnd(HWND * pVal)
  60. {
  61. *pVal = m_wndList.m_hWnd;
  62. return S_OK;
  63. }
  64. STDMETHODIMP CConfExplorerDetailsView::put_hWnd(HWND newVal)
  65. {
  66. // Load up image lists items for conferences
  67. if ( IsWindow(newVal) )
  68. {
  69. // Make sure the window isn't already subclassed
  70. if ( m_wndList.m_hWnd ) m_wndList.UnsubclassWindow();
  71. // Load listbox with items
  72. if ( m_wndList.SubclassWindow(newVal))
  73. {
  74. // Take over window to get sorting messages and other things
  75. m_wndList.m_pDetailsView = this;
  76. m_wndList.PostMessage( WM_MYCREATE, 0, 0 );
  77. }
  78. }
  79. else if ( IsWindow(m_wndList.m_hWnd) )
  80. {
  81. put_Columns();
  82. DeleteAllItems();
  83. m_wndList.UnsubclassWindow();
  84. m_wndList.m_pDetailsView = NULL;
  85. m_wndList.m_hWnd = NULL;
  86. }
  87. return S_OK;
  88. }
  89. bool CConfExplorerDetailsView::IsSortColumnDateBased(int nCol) const
  90. {
  91. bool bRet = false;
  92. switch ( nCol )
  93. {
  94. case COL_STARTS:
  95. case COL_ENDS:
  96. bRet = true;
  97. break;
  98. }
  99. return bRet;
  100. }
  101. int CConfExplorerDetailsView::GetSecondarySortColumn() const
  102. {
  103. return (m_nSortColumn) ? COL_NAME : COL_STARTS;
  104. }
  105. void CConfExplorerDetailsView::get_Columns()
  106. {
  107. #define CONFEXP_DEFAULT_WIDTH 125
  108. // Load column settings from registry
  109. USES_CONVERSION;
  110. CRegKey regKey;
  111. TCHAR szReg[255], szEntry[50];
  112. LV_COLUMN lvc;
  113. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  114. lvc.fmt = LVCFMT_LEFT;
  115. lvc.pszText = szReg;
  116. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_VIEW_KEY, szReg, ARRAYSIZE(szReg) );
  117. regKey.Open( HKEY_CURRENT_USER, szReg, KEY_READ );
  118. // Add the columns.
  119. for ( int i = 0; i < ARRAYSIZE(arCols); i++ )
  120. {
  121. lvc.iSubItem = i;
  122. lvc.cx = CONFEXP_DEFAULT_WIDTH;
  123. // Load registry stuff if exists
  124. if ( regKey.m_hKey )
  125. {
  126. DWORD dwVal = 0;
  127. // Get sort column and sort direction
  128. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_SORT_COLUMN, szReg, ARRAYSIZE(szReg) );
  129. regKey.QueryValue( dwVal, szReg );
  130. m_nSortColumn = (int) max(0, ((int)min(dwVal,ARRAYSIZE(arCols))));
  131. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_SORT_ASCENDING, szReg, ARRAYSIZE(szReg) );
  132. regKey.QueryValue( dwVal, szReg );
  133. m_bSortAscending = (bool) (dwVal > 0);
  134. // Column Widths
  135. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_ENTRY, szReg, ARRAYSIZE(szReg) );
  136. _sntprintf( szEntry, ARRAYSIZE(szEntry), szReg, i );
  137. szEntry[ARRAYSIZE(szEntry)-1] = _T('\0');
  138. dwVal = 0;
  139. if ( (regKey.QueryValue(dwVal, szEntry) == ERROR_SUCCESS) && (dwVal > 0) )
  140. lvc.cx = (int) max(MIN_COL_WIDTH, min( 5000, dwVal ));
  141. }
  142. LoadString( _Module.GetResourceInstance(), arCols[i], szReg, ARRAYSIZE(szReg) );
  143. ListView_InsertColumn( m_wndList.m_hWnd, i, &lvc );
  144. }
  145. }
  146. void CConfExplorerDetailsView::put_Columns()
  147. {
  148. // Save column setting to registry
  149. USES_CONVERSION;
  150. CRegKey regKey;
  151. TCHAR szReg[100], szEntry[50];
  152. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_VIEW_KEY, szReg, ARRAYSIZE(szReg) );
  153. if ( regKey.Create(HKEY_CURRENT_USER, szReg) == ERROR_SUCCESS )
  154. {
  155. // Save sort column and sort direction
  156. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_SORT_COLUMN, szReg, ARRAYSIZE(szReg) );
  157. regKey.SetValue( m_nSortColumn, szReg );
  158. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_SORT_ASCENDING, szReg, ARRAYSIZE(szReg) );
  159. regKey.SetValue( m_bSortAscending, szReg );
  160. // Save column widths
  161. int nWidth;
  162. for ( int i = 0; i < ARRAYSIZE(arCols); i++ )
  163. {
  164. nWidth = ListView_GetColumnWidth( m_wndList.m_hWnd, i );
  165. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFSERV_ENTRY, szReg, ARRAYSIZE(szReg) );
  166. _sntprintf( szEntry, ARRAYSIZE(szEntry), szReg, i );
  167. szEntry[ARRAYSIZE(szEntry)-1] = _T('\0');
  168. regKey.SetValue( nWidth, szEntry );
  169. }
  170. }
  171. }
  172. STDMETHODIMP CConfExplorerDetailsView::Refresh()
  173. {
  174. HRESULT hr;
  175. IConfExplorer *pConfExplorer;
  176. if ( SUCCEEDED(hr = get_ConfExplorer(&pConfExplorer)) )
  177. {
  178. // Show hourglass
  179. HCURSOR hCurOld = SetCursor( LoadCursor(NULL, IDC_WAIT) );
  180. IConfExplorerTreeView *pView;
  181. if ( SUCCEEDED(hr = pConfExplorer->get_TreeView(&pView)) )
  182. {
  183. BSTR bstrLocation = NULL, bstrServer = NULL;
  184. if ( SUCCEEDED(hr = pView->GetSelection(&bstrLocation, &bstrServer)) )
  185. {
  186. pView->ForceConfServerForEnum( bstrServer );
  187. DeleteAllItems();
  188. }
  189. SysFreeString( bstrLocation );
  190. SysFreeString( bstrServer );
  191. pView->Release();
  192. }
  193. put_Columns();
  194. // Restore wait cursor
  195. SetCursor( hCurOld );
  196. pConfExplorer->Release();
  197. }
  198. return hr;
  199. }
  200. HRESULT CConfExplorerDetailsView::ShowConferencesAndPersons(BSTR bstrServer )
  201. {
  202. USES_CONVERSION;
  203. IConfExplorer *pConfExplorer;
  204. ITDirectory *pDir;
  205. //
  206. // We should initialize the ocal variable
  207. //
  208. HRESULT hr = E_FAIL;
  209. if ( SUCCEEDED(get_ConfExplorer(&pConfExplorer)) )
  210. {
  211. if ( SUCCEEDED(hr = pConfExplorer->get_ConfDirectory(NULL, (IDispatch **) &pDir)) )
  212. {
  213. // Enumerate through conferences adding them as we go along
  214. IEnumDirectoryObject *pEnum;
  215. ITDirectoryObject *pITDirObject;
  216. long nCount;
  217. // Enumerate list of conferences
  218. if ( SUCCEEDED(hr = pDir->EnumerateDirectoryObjects(OT_CONFERENCE, A2BSTR("*"), &pEnum)) )
  219. {
  220. nCount = 0;
  221. m_critConfList.Lock();
  222. DELETE_LIST(m_lstConfs);
  223. while ( (nCount++ < MAX_ENUMLISTSIZE) && ((hr = pEnum->Next(1, &pITDirObject, NULL)) == S_OK) )
  224. {
  225. _ASSERT( pITDirObject );
  226. CConfDetails *p = AddListItem( bstrServer, pITDirObject, m_lstConfs );
  227. pITDirObject->Release();
  228. }
  229. m_critConfList.Unlock();
  230. pEnum->Release();
  231. }
  232. // Retrieve the people in the ILS server
  233. if ( SUCCEEDED(hr = pDir->EnumerateDirectoryObjects(OT_USER, A2BSTR("*"), &pEnum)) )
  234. {
  235. nCount = 0;
  236. m_critConfList.Lock();
  237. DELETE_LIST(m_lstPersons);
  238. while ( (nCount++ < MAX_ENUMLISTSIZE) && ((hr = pEnum->Next(1, &pITDirObject, NULL)) == S_OK) )
  239. {
  240. _ASSERT( pITDirObject );
  241. CPersonDetails *p = AddListItemPerson( bstrServer, pITDirObject, m_lstPersons );
  242. pITDirObject->Release();
  243. }
  244. m_critConfList.Unlock();
  245. pEnum->Release();
  246. }
  247. pDir->Release();
  248. // Put conferences in the listbox
  249. UpdateConfList( NULL );
  250. }
  251. pConfExplorer->Release();
  252. }
  253. return hr;
  254. }
  255. STDMETHODIMP CConfExplorerDetailsView::get_Selection(DATE *pdateStart, DATE *pdateEnd, BSTR *pVal )
  256. {
  257. if ( !IsWindow(m_wndList.m_hWnd) ) return E_PENDING;
  258. HRESULT hr = E_FAIL;
  259. m_critConfList.Lock();
  260. for ( int i = 0; i < ListView_GetItemCount(m_wndList.m_hWnd); i++ )
  261. {
  262. if ( ListView_GetItemState(m_wndList.m_hWnd, i, LVIS_SELECTED) )
  263. {
  264. LV_ITEM lvi = {0};
  265. lvi.iItem = i;
  266. lvi.mask = LVIF_PARAM;
  267. if ( ListView_GetItem(m_wndList.m_hWnd, &lvi) && lvi.lParam )
  268. {
  269. *pVal = SysAllocString( ((CConfDetails *) lvi.lParam)->m_bstrName );
  270. if ( pdateStart ) *pdateStart = ((CConfDetails *) lvi.lParam)->m_dateStart;
  271. if ( pdateEnd ) *pdateEnd = ((CConfDetails *) lvi.lParam)->m_dateEnd;
  272. hr = S_OK;
  273. break;
  274. }
  275. }
  276. }
  277. m_critConfList.Unlock();
  278. return hr;
  279. }
  280. STDMETHODIMP CConfExplorerDetailsView::get_ConfExplorer(IConfExplorer **ppVal)
  281. {
  282. HRESULT hr = E_PENDING;
  283. Lock();
  284. if ( m_pIConfExplorer )
  285. hr = m_pIConfExplorer->QueryInterface(IID_IConfExplorer, (void **) ppVal );
  286. Unlock();
  287. return hr;
  288. }
  289. STDMETHODIMP CConfExplorerDetailsView::put_ConfExplorer(IConfExplorer * newVal)
  290. {
  291. HRESULT hr = S_OK;
  292. Lock();
  293. RELEASE( m_pIConfExplorer );
  294. if ( newVal )
  295. hr = newVal->QueryInterface( IID_IConfExplorer, (void **) &m_pIConfExplorer );
  296. Unlock();
  297. return hr;
  298. }
  299. STDMETHODIMP CConfExplorerDetailsView::OnColumnClicked(long nColumn)
  300. {
  301. ATLTRACE(_T(".enter.CConfExplorerDetailsView::OnColumnClicked(%ld).\n"), nColumn );
  302. if ( !IsWindow(m_wndList.m_hWnd) ) return E_PENDING;
  303. if ( ListView_GetColumnWidth(m_wndList.m_hWnd, nColumn) == 0 ) return E_INVALIDARG;
  304. // Sort on column selected; if new column sort ascending
  305. if ( m_nSortColumn == nColumn )
  306. {
  307. m_bSortAscending = !m_bSortAscending;
  308. }
  309. else
  310. {
  311. m_nSortColumn = nColumn;
  312. m_bSortAscending = true;
  313. }
  314. ListView_SortItems( m_wndList.m_hWnd, CompareFunc, (LPARAM) this );
  315. return S_OK;
  316. }
  317. void CConfExplorerDetailsView::DeleteAllItems()
  318. {
  319. if ( IsWindow(m_wndList.m_hWnd) )
  320. ListView_DeleteAllItems( m_wndList.m_hWnd );
  321. DELETE_CRITLIST(m_lstConfs, m_critConfList);
  322. DELETE_CRITLIST(m_lstPersons, m_critConfList);
  323. }
  324. long CConfExplorerDetailsView::OnGetDispInfo( LV_DISPINFO *pInfo )
  325. {
  326. USES_CONVERSION;
  327. if ( pInfo && (pInfo->hdr.hwndFrom == m_wndList.m_hWnd) )
  328. {
  329. switch( pInfo->hdr.code )
  330. {
  331. case LVN_GETDISPINFO:
  332. // Write out the text
  333. if ( pInfo->item.lParam )
  334. {
  335. CConfDetails *pDetails = (CConfDetails *) pInfo->item.lParam;
  336. ///////////////////////////////////////////// Set image for item
  337. if ( pInfo->item.mask & LVIF_IMAGE )
  338. {
  339. CComPtr<IAVGeneralNotification> pAVGen;
  340. if ( SUCCEEDED(_Module.get_AVGenNot(&pAVGen)) && (pAVGen->fire_IsReminderSet(pDetails->m_bstrServer, pDetails->m_bstrName) == S_OK) )
  341. {
  342. // User has set a reminder
  343. pInfo->item.iImage = IMAGE_REMINDER;
  344. }
  345. else
  346. {
  347. // Is the conference in session
  348. DATE dateNow;
  349. SYSTEMTIME st;
  350. GetLocalTime( &st );
  351. SystemTimeToVariantTime( &st, &dateNow );
  352. DATE dateStart = pDetails->m_dateStart - (DATE) (.125 / 12 ); // drop back 15 minutes
  353. if ( (dateStart <= dateNow) && (pDetails->m_dateEnd >= dateNow) )
  354. pInfo->item.iImage = IMAGE_INSESSION;
  355. else
  356. pInfo->item.iImage = IMAGE_NONE;
  357. }
  358. }
  359. ////////////////////////////////////////////////////////// item state
  360. if ( pInfo->item.mask & LVIF_STATE )
  361. {
  362. // What type of media does the conference support?
  363. switch ( pDetails->m_sdp.m_nConfMediaType )
  364. {
  365. case CConfSDP::MEDIA_AUDIO:
  366. pInfo->item.state += INDEXTOSTATEIMAGEMASK( IMAGE_STATE_AUDIO );
  367. break;
  368. case CConfSDP::MEDIA_VIDEO:
  369. pInfo->item.state += INDEXTOSTATEIMAGEMASK( IMAGE_STATE_VIDEO );
  370. break;
  371. }
  372. }
  373. ///////////////////////////////////////// Set text for item
  374. if ( pInfo->item.mask & LVIF_TEXT )
  375. {
  376. BSTR bstrTemp = NULL;
  377. switch ( pInfo->item.iSubItem )
  378. {
  379. case COL_NAME: bstrTemp = SysAllocString( pDetails->m_bstrName ); break;
  380. case COL_PURPOSE: bstrTemp = SysAllocString( pDetails->m_bstrDescription ); break;
  381. case COL_ORIGINATOR: bstrTemp = SysAllocString( pDetails->m_bstrOriginator ); break;
  382. case COL_STARTS: VarBstrFromDate( pDetails->m_dateStart, LOCALE_USER_DEFAULT, NULL, &bstrTemp ); break;
  383. case COL_ENDS: VarBstrFromDate( pDetails->m_dateEnd, LOCALE_USER_DEFAULT, NULL, &bstrTemp ); break;
  384. default: _ASSERT( false );
  385. }
  386. // Copy string
  387. _tcsncpy( pInfo->item.pszText, (bstrTemp) ? OLE2CT(bstrTemp) : _T(""), pInfo->item.cchTextMax );
  388. pInfo->item.pszText[pInfo->item.cchTextMax - 1] = 0;
  389. SysFreeString( bstrTemp );
  390. }
  391. }
  392. break;
  393. case LVN_SETDISPINFO:
  394. break;
  395. }
  396. }
  397. return 0;
  398. }
  399. STDMETHODIMP CConfExplorerDetailsView::UpdateConfList(long * pList)
  400. {
  401. // Keep count on the number of requests to update the conference
  402. m_critUpdateList.Lock();
  403. m_nUpdateCount++;
  404. m_critUpdateList.Unlock();
  405. // If failed, request is queued
  406. if ( TryEnterCriticalSection(&m_critConfList.m_sec) == FALSE )
  407. return E_PENDING;
  408. // Disable redraw
  409. ::SendMessage( m_wndList.m_hWnd, WM_SETREDRAW, false, 0 );
  410. for ( ;; )
  411. {
  412. // Check to see how many times we need to update the conference list
  413. m_critUpdateList.Lock();
  414. if ( m_nUpdateCount == 0 )
  415. break;
  416. else
  417. m_nUpdateCount--;
  418. m_critUpdateList.Unlock();
  419. ///////////////////////////////////////////////////////////////////////////////////
  420. // Clear out all items from the listbox
  421. ListView_DeleteAllItems( m_wndList.m_hWnd );
  422. // Copy list over
  423. CONFDETAILSLIST::iterator i, iEnd;
  424. if ( pList )
  425. {
  426. DELETE_LIST(m_lstConfs);
  427. iEnd = ((CONFDETAILSLIST *) pList)->end();
  428. for ( i = ((CONFDETAILSLIST *) pList)->begin(); i != iEnd; i++ )
  429. {
  430. CConfDetails *pDetails = new CConfDetails;
  431. if ( pDetails )
  432. {
  433. *pDetails = *(*i);
  434. m_lstConfs.push_back( pDetails );
  435. }
  436. }
  437. }
  438. // Populate the details view
  439. LV_ITEM lvi = {0};
  440. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  441. lvi.pszText = LPSTR_TEXTCALLBACK;
  442. lvi.iImage = I_IMAGECALLBACK;
  443. iEnd = m_lstConfs.end();
  444. for ( i = m_lstConfs.begin(); i != iEnd; i++ )
  445. {
  446. lvi.lParam = (LPARAM) *i;
  447. ListView_InsertItem( m_wndList.m_hWnd, &lvi );
  448. }
  449. }
  450. // Enable redraw prior to exiting crit
  451. ::SendMessage( m_wndList.m_hWnd, WM_SETREDRAW, true, 0 );
  452. m_critConfList.Unlock();
  453. m_critUpdateList.Unlock();
  454. // Sort the list of items
  455. ListView_SortItems( m_wndList.m_hWnd, CompareFunc, (LPARAM) this );
  456. ::InvalidateRect(m_wndList.m_hWnd, NULL, true);
  457. return S_OK;
  458. }
  459. CConfDetails* CConfExplorerDetailsView::AddListItem( BSTR bstrServer, ITDirectoryObject *pITDirObject, CONFDETAILSLIST& lstConfs )
  460. {
  461. _ASSERT( pITDirObject );
  462. USES_CONVERSION;
  463. // Create list box item and add to list
  464. CConfDetails *p = new CConfDetails;
  465. if ( p )
  466. {
  467. p->Populate( bstrServer, pITDirObject );
  468. lstConfs.push_front( p );
  469. }
  470. return NULL;
  471. }
  472. CPersonDetails* CConfExplorerDetailsView::AddListItemPerson( BSTR bstrServer, ITDirectoryObject *pITDirObject, PERSONDETAILSLIST& lstPersons )
  473. {
  474. _ASSERT( pITDirObject );
  475. USES_CONVERSION;
  476. // Create list box item and add to list
  477. CPersonDetails *p = new CPersonDetails;
  478. if ( p )
  479. {
  480. p->Populate( bstrServer, pITDirObject );
  481. lstPersons.push_front( p );
  482. }
  483. return NULL;
  484. }
  485. STDMETHODIMP CConfExplorerDetailsView::get_bSortAscending(VARIANT_BOOL * pVal)
  486. {
  487. Lock();
  488. *pVal = m_bSortAscending;
  489. Unlock();
  490. return S_OK;
  491. }
  492. STDMETHODIMP CConfExplorerDetailsView::get_nSortColumn(long * pVal)
  493. {
  494. Lock();
  495. *pVal = m_nSortColumn;
  496. Unlock();
  497. return S_OK;
  498. }
  499. STDMETHODIMP CConfExplorerDetailsView::put_nSortColumn(long newVal)
  500. {
  501. return OnColumnClicked( newVal );
  502. }
  503. STDMETHODIMP CConfExplorerDetailsView::IsConferenceSelected()
  504. {
  505. if ( !IsWindow(m_wndList.m_hWnd) ) return E_PENDING;
  506. for ( int i = 0; i < ListView_GetItemCount(m_wndList.m_hWnd); i++ )
  507. {
  508. if ( ListView_GetItemState(m_wndList.m_hWnd, i, LVIS_SELECTED) )
  509. return S_OK;
  510. }
  511. return S_FALSE;
  512. }
  513. STDMETHODIMP CConfExplorerDetailsView::get_SelectedConfDetails(long ** ppVal)
  514. {
  515. if ( !IsWindow(m_wndList.m_hWnd) ) return E_PENDING;
  516. HRESULT hr = E_FAIL;
  517. m_critConfList.Lock();
  518. for ( int i = 0; i < ListView_GetItemCount(m_wndList.m_hWnd); i++ )
  519. {
  520. if ( ListView_GetItemState(m_wndList.m_hWnd, i, LVIS_SELECTED) )
  521. {
  522. LV_ITEM lvi = {0};
  523. lvi.iItem = i;
  524. lvi.mask = LVIF_PARAM;
  525. if ( ListView_GetItem(m_wndList.m_hWnd, &lvi) && lvi.lParam )
  526. {
  527. CConfDetails *pNew = new CConfDetails;
  528. if ( pNew )
  529. {
  530. // copy this over
  531. *pNew = *((CConfDetails *) lvi.lParam);
  532. *ppVal = (long *) pNew;
  533. hr = S_OK;
  534. }
  535. break;
  536. }
  537. }
  538. }
  539. m_critConfList.Unlock();
  540. return hr;
  541. }