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.

1445 lines
30 KiB

  1. //
  2. // Copyright 2001 - Microsoft Corporation
  3. //
  4. //
  5. // Created By:
  6. // Geoff Pease (GPease) 23-JAN-2001
  7. //
  8. // Maintained By:
  9. // Geoff Pease (GPease) 23-JAN-2001
  10. //
  11. #include "pch.h"
  12. #include "DocProp.h"
  13. #include "DefProp.h"
  14. #include "IEditVariantsInPlace.h"
  15. #include "PropertyCacheItem.h"
  16. #include "PropertyCache.h"
  17. #include "AdvancedDlg.h"
  18. #include "shutils.h"
  19. #include "WMUser.h"
  20. #include "IEditVariantsInPlace.h"
  21. #include "EditTypeItem.h"
  22. #pragma hdrstop
  23. DEFINE_THISCLASS( "CAdvancedDlg" )
  24. //
  25. // This value is the offset of images in the bitmap representing the
  26. // icons when multiple documents have been selected.
  27. //
  28. #define MULTIDOC_IMAGE_OFFSET_VALUE 2
  29. // ************************************************************************
  30. //
  31. // Constructor / Destructor
  32. //
  33. // ************************************************************************
  34. //
  35. // Return Values:
  36. // S_OK
  37. // A new CAdvancedDlg was created successfully.
  38. //
  39. // E_OUTOFMEMORY
  40. // Out of memory.
  41. //
  42. // other HRESULTs.
  43. //
  44. HRESULT
  45. CAdvancedDlg::CreateInstance(
  46. CAdvancedDlg ** pAdvDlgOut
  47. , HWND hwndParentIn
  48. )
  49. {
  50. TraceFunc( "" );
  51. HRESULT hr;
  52. Assert( pAdvDlgOut != NULL );
  53. CAdvancedDlg * pthis = new CAdvancedDlg;
  54. if ( pthis != NULL )
  55. {
  56. hr = THR( pthis->Init( hwndParentIn ) );
  57. if ( SUCCEEDED( hr ) )
  58. {
  59. *pAdvDlgOut = pthis;
  60. (*pAdvDlgOut)->AddRef( );
  61. }
  62. pthis->Release( );
  63. }
  64. else
  65. {
  66. hr = E_OUTOFMEMORY;
  67. }
  68. HRETURN( hr );
  69. }
  70. //
  71. // Constructor
  72. //
  73. CAdvancedDlg::CAdvancedDlg( void )
  74. : _cRef( 1 )
  75. {
  76. TraceFunc( "" );
  77. Assert( 1 == _cRef );
  78. Assert( NULL == _hwndParent );
  79. Assert( NULL == _hdlg );
  80. Assert( NULL == _hwndList );
  81. Assert( NULL == _pEdit );
  82. Assert( NULL == _pItem );
  83. InterlockedIncrement( &g_cObjects );
  84. TraceFuncExit();
  85. }
  86. //
  87. // Description:
  88. // Intializes the instance of the class. Put things that can
  89. // fail into this method.
  90. //
  91. HRESULT
  92. CAdvancedDlg::Init(
  93. HWND hwndParentIn
  94. )
  95. {
  96. TraceFunc( "" );
  97. HRESULT hr = S_OK;
  98. _hwndParent = hwndParentIn;
  99. // IUnknown stuff
  100. Assert( _cRef == 1 );
  101. //
  102. // Initialize the common controls
  103. //
  104. INITCOMMONCONTROLSEX iccx = { sizeof(INITCOMMONCONTROLSEX)
  105. , ICC_LISTVIEW_CLASSES | ICC_USEREX_CLASSES | ICC_DATE_CLASSES
  106. };
  107. BOOL b = TBOOL( InitCommonControlsEx( &iccx ) );
  108. if ( !b )
  109. goto ErrorGLE;
  110. //
  111. // Create the dialog
  112. //
  113. _hdlg = CreateDialogParam( g_hInstance
  114. , MAKEINTRESOURCE(IDD_ADVANCEDVIEW)
  115. , _hwndParent
  116. , DlgProc
  117. , (LPARAM) this
  118. );
  119. if ( NULL == _hdlg )
  120. goto ErrorGLE;
  121. Cleanup:
  122. HRETURN( hr );
  123. ErrorGLE:
  124. {
  125. DWORD dwErr = TW32( GetLastError( ) );
  126. hr = HRESULT_FROM_WIN32( dwErr );
  127. }
  128. goto Cleanup;
  129. }
  130. //
  131. // Destructor
  132. //
  133. CAdvancedDlg::~CAdvancedDlg( )
  134. {
  135. TraceFunc( "" );
  136. if ( NULL != _pEdit )
  137. {
  138. _pEdit->Release( );
  139. }
  140. if ( NULL != _hdlg )
  141. {
  142. DestroyWindow( _hdlg );
  143. }
  144. InterlockedDecrement( &g_cObjects );
  145. TraceFuncExit();
  146. }
  147. // ************************************************************************
  148. //
  149. // IUnknown
  150. //
  151. // ************************************************************************
  152. //
  153. // QueryInterface
  154. //
  155. STDMETHODIMP
  156. CAdvancedDlg::QueryInterface(
  157. REFIID riid,
  158. LPVOID *ppv
  159. )
  160. {
  161. TraceQIFunc( riid, ppv );
  162. HRESULT hr = E_NOINTERFACE;
  163. if ( IsEqualIID( riid, __uuidof(IUnknown) ) )
  164. {
  165. *ppv = static_cast< IUnknown * >( this );
  166. hr = S_OK;
  167. }
  168. #if 0
  169. else if ( IsEqualIID( riid, __uuidof(IShellExtInit) ) )
  170. {
  171. *ppv = TraceInterface( __THISCLASS__, IShellExtInit, this, 0 );
  172. hr = S_OK;
  173. }
  174. #endif
  175. if ( SUCCEEDED( hr ) )
  176. {
  177. ((IUnknown*) *ppv)->AddRef( );
  178. }
  179. QIRETURN( hr, riid );
  180. }
  181. //
  182. // AddRef
  183. //
  184. STDMETHODIMP_(ULONG)
  185. CAdvancedDlg::AddRef( void )
  186. {
  187. TraceFunc( "[IUnknown]" );
  188. _cRef ++; // apartment
  189. RETURN( _cRef );
  190. }
  191. //
  192. // Release
  193. //
  194. STDMETHODIMP_(ULONG)
  195. CAdvancedDlg::Release( void )
  196. {
  197. TraceFunc( "[IUnknown]" );
  198. _cRef --; // apartment
  199. if ( 0 != _cRef )
  200. RETURN( _cRef );
  201. delete this;
  202. RETURN( 0 );
  203. }
  204. // ***************************************************************************
  205. //
  206. // Dialog Proc and Property Sheet Callback
  207. //
  208. // ***************************************************************************
  209. //
  210. // DlgProc
  211. //
  212. INT_PTR CALLBACK
  213. CAdvancedDlg::DlgProc(
  214. HWND hDlgIn
  215. , UINT uMsgIn
  216. , WPARAM wParam
  217. , LPARAM lParam
  218. )
  219. {
  220. // Don't do TraceFunc because every mouse movement will cause this function to be called.
  221. WndMsg( hDlgIn, uMsgIn, wParam, lParam );
  222. LRESULT lr = FALSE;
  223. CAdvancedDlg * pPage = (CAdvancedDlg *) GetWindowLongPtr( hDlgIn, DWLP_USER );
  224. if ( uMsgIn == WM_INITDIALOG )
  225. {
  226. SetWindowLongPtr( hDlgIn, DWLP_USER, lParam );
  227. pPage = (CAdvancedDlg *) lParam ;
  228. pPage->_hdlg = hDlgIn;
  229. }
  230. if ( pPage != NULL )
  231. {
  232. Assert( hDlgIn == pPage->_hdlg );
  233. switch( uMsgIn )
  234. {
  235. case WM_INITDIALOG:
  236. lr = pPage->OnInitDialog( );
  237. break;
  238. case WM_COMMAND:
  239. lr = pPage->OnCommand( HIWORD(wParam), LOWORD(wParam), LPARAM(lParam) );
  240. break;
  241. case WM_NOTIFY:
  242. lr = pPage->OnNotify( (int) wParam, (LPNMHDR) lParam );
  243. break;
  244. case WM_SETFOCUS:
  245. lr = SendMessage( pPage->_hwndList, WM_SETFOCUS, wParam, lParam );
  246. break;
  247. case WM_DESTROY:
  248. SetWindowLongPtr( hDlgIn, DWLP_USER, NULL );
  249. lr = pPage->OnDestroy( );
  250. break;
  251. case WM_HELP:
  252. lr = pPage->OnHelp( (LPHELPINFO) lParam );
  253. break;
  254. case WM_CONTEXTMENU:
  255. lr = pPage->OnContextMenu( (HWND) wParam, LOWORD(lParam), HIWORD(lParam) );
  256. break;
  257. }
  258. }
  259. return lr;
  260. }
  261. //
  262. // ListViewSubProc
  263. //
  264. LRESULT CALLBACK
  265. CAdvancedDlg::ListViewSubclassProc(
  266. HWND hwndIn
  267. , UINT uMsgIn
  268. , WPARAM wParam
  269. , LPARAM lParam
  270. , UINT_PTR uIdSubclassIn
  271. , DWORD_PTR dwRefDataIn
  272. )
  273. {
  274. // Don't do TraceFunc because every mouse movement will cause this function to be called.
  275. WndMsg( hwndIn, uMsgIn, wParam, lParam );
  276. LRESULT lr = FALSE;
  277. CAdvancedDlg * pPage = (CAdvancedDlg *) dwRefDataIn;
  278. Assert( NULL != pPage );
  279. Assert( hwndIn == pPage->_hwndList );
  280. Assert( IDC_PROPERTIES == uIdSubclassIn );
  281. switch( uMsgIn )
  282. {
  283. case WM_COMMAND:
  284. return pPage->List_OnCommand( LOWORD(wParam), HIWORD(wParam), lParam );
  285. case WM_NOTIFY:
  286. return pPage->List_OnNotify( (int) wParam, (LPNMHDR) lParam );
  287. case WM_VSCROLL:
  288. return pPage->List_OnVertScroll( LOWORD(wParam), HIWORD(wParam), (HWND) lParam );
  289. case WM_HSCROLL:
  290. return pPage->List_OnHornScroll( LOWORD(wParam), HIWORD(wParam), (HWND) lParam );
  291. case WM_CHAR:
  292. return pPage->List_OnChar( (UINT) wParam, lParam );
  293. case WM_KEYDOWN:
  294. return pPage->List_OnKeyDown( (UINT) wParam, lParam );
  295. }
  296. return DefSubclassProc( hwndIn, uMsgIn, wParam, lParam );
  297. }
  298. // ***************************************************************************
  299. //
  300. // Private methods
  301. //
  302. // ***************************************************************************
  303. //
  304. // WM_INITDIALOG handler
  305. //
  306. LRESULT
  307. CAdvancedDlg::OnInitDialog( void )
  308. {
  309. TraceFunc( "" );
  310. int iSize;
  311. LVCOLUMN lvc;
  312. TCHAR szTitle[ 64 ]; // random
  313. ULONG idxFolder;
  314. HIMAGELIST hil;
  315. LRESULT lr = TRUE; // set the focus
  316. Assert( NULL != _hdlg ); // this should have been initialized in the DlgProc.
  317. _hwndList = GetDlgItem( _hdlg, IDC_PROPERTIES );
  318. TBOOL( NULL != _hwndList );
  319. //
  320. // Enable ListView for Grouping mode.
  321. //
  322. SetWindowLongPtr( _hwndList, GWL_STYLE, GetWindowLongPtr( _hwndList, GWL_STYLE ) | LVS_AUTOARRANGE | LVS_SHOWSELALWAYS);
  323. ListView_SetExtendedListViewStyle( _hwndList, LVS_EX_FULLROWSELECT );
  324. ListView_EnableGroupView( _hwndList, TRUE );
  325. //
  326. // Add the image list
  327. //
  328. hil = ImageList_LoadImage( g_hInstance
  329. , MAKEINTRESOURCE(IDB_TREE_IMAGELIST)
  330. , 16
  331. , 0
  332. , RGB(255,0,255)
  333. , IMAGE_BITMAP
  334. , LR_SHARED
  335. );
  336. hil = ListView_SetImageList( _hwndList
  337. , hil
  338. , LVSIL_SMALL
  339. );
  340. Assert( NULL == hil ); // there shouldn't have been a previous image list.
  341. //
  342. // Setup up common values.
  343. //
  344. lvc.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
  345. lvc.fmt = LVCFMT_LEFT;
  346. lvc.pszText = szTitle;
  347. //
  348. // Add Column 0
  349. //
  350. lvc.iSubItem = 0;
  351. iSize = LoadString( g_hInstance, IDS_PROPERTY_HEADER_ITEM, szTitle, ARRAYSIZE(szTitle) );
  352. AssertMsg( 0 != iSize, "Missing string resource?" );
  353. ListView_InsertColumn( _hwndList, 0, &lvc );
  354. //
  355. // Add Column 1
  356. //
  357. lvc.iSubItem = 1;
  358. iSize = LoadString( g_hInstance, IDS_VALUE_HEADER_ITEM, szTitle, ARRAYSIZE(szTitle) );
  359. AssertMsg( 0 != iSize, "Missing string resource?" );
  360. ListView_InsertColumn( _hwndList, 1, &lvc );
  361. //
  362. // Add the groups - In the end, if a group contains no items, the group
  363. // header will not be shown.
  364. //
  365. for ( idxFolder = 0; NULL != g_rgTopLevelFolders[ idxFolder ].pPFID; idxFolder ++ )
  366. {
  367. //
  368. // Add the property folder as a group item.
  369. //
  370. int iRet;
  371. WCHAR szBuf[ 256 ]; // random
  372. iRet = LoadString( g_hInstance, g_rgTopLevelFolders[ idxFolder ].nIDStringRes, szBuf, ARRAYSIZE(szBuf) );
  373. AssertMsg( 0 != iRet, "Missing resource?" );
  374. if ( 0 == iRet )
  375. continue;
  376. LVGROUP lvg;
  377. lvg.cbSize = sizeof(LVGROUP);
  378. lvg.mask = LVGF_HEADER | LVGF_GROUPID;
  379. lvg.iGroupId = idxFolder;
  380. lvg.pszHeader = szBuf;
  381. LRESULT iItem = ListView_InsertGroup( _hwndList, -1, &lvg );
  382. TBOOL( -1 != iItem );
  383. }
  384. //
  385. // Subclass the listview
  386. //
  387. TBOOL( SetWindowSubclass( _hwndList, ListViewSubclassProc, IDC_PROPERTIES, (DWORD_PTR) this ) );
  388. RETURN( lr );
  389. }
  390. //
  391. // WM_COMMAND handler
  392. //
  393. LRESULT
  394. CAdvancedDlg::OnCommand(
  395. WORD wCodeIn
  396. , WORD wCtlIn
  397. , LPARAM lParam
  398. )
  399. {
  400. TraceFunc( "" );
  401. LRESULT lr = FALSE;
  402. switch ( wCtlIn )
  403. {
  404. case IDC_SIMPLE:
  405. if ( BN_CLICKED == wCodeIn )
  406. {
  407. THR( (HRESULT) SendMessage( _hwndParent, WMU_TOGGLE, 0, 0 ) );
  408. }
  409. break;
  410. }
  411. RETURN( lr );
  412. }
  413. //
  414. // WM_NOTIFY handler
  415. //
  416. LRESULT
  417. CAdvancedDlg::OnNotify(
  418. int iCtlIdIn
  419. , LPNMHDR pnmhIn
  420. )
  421. {
  422. TraceFunc( "" );
  423. LRESULT lr = FALSE;
  424. switch( pnmhIn->code )
  425. {
  426. case NM_CLICK:
  427. lr = OnNotifyClick( (LPNMITEMACTIVATE) pnmhIn );
  428. break;
  429. }
  430. RETURN( lr );
  431. }
  432. //
  433. // NM_CLICK handler
  434. //
  435. LRESULT
  436. CAdvancedDlg::OnNotifyClick(
  437. LPNMITEMACTIVATE pnmIn
  438. )
  439. {
  440. TraceFunc( "" );
  441. LRESULT lr = S_FALSE;
  442. INT iItem;
  443. Assert( NULL != pnmIn );
  444. if ( -1 == pnmIn->iItem )
  445. {
  446. LVHITTESTINFO lvhti;
  447. lvhti.pt = pnmIn->ptAction;
  448. iItem = ListView_SubItemHitTest( _hwndList, &lvhti );
  449. if ( -1 == iItem )
  450. goto Cleanup;
  451. if ( 1 != lvhti.iSubItem )
  452. goto Cleanup;
  453. }
  454. else
  455. {
  456. if ( 1 != pnmIn->iSubItem )
  457. goto Cleanup;
  458. iItem = pnmIn->iItem;
  459. }
  460. STHR( CreateControlForProperty( iItem ) );
  461. Cleanup:
  462. RETURN( lr );
  463. }
  464. //
  465. // WM_NOTIFY handler for the ListView Subclass
  466. //
  467. LRESULT
  468. CAdvancedDlg::List_OnNotify(
  469. int iCtlIdIn
  470. , LPNMHDR pnmhIn
  471. )
  472. {
  473. TraceFunc( "" );
  474. LRESULT lr;
  475. switch( pnmhIn->code )
  476. {
  477. case NM_KILLFOCUS:
  478. if ( NULL != _pEdit )
  479. {
  480. STHR( PersistControlInProperty( ) );
  481. _pEdit->Release( );
  482. _pEdit = NULL;
  483. }
  484. break;
  485. }
  486. lr = DefSubclassProc( _hwndList, WM_NOTIFY, (WPARAM) iCtlIdIn, (LPARAM) pnmhIn );
  487. RETURN( lr );
  488. }
  489. //
  490. // WM_COMMAND handler for the ListView Subclass
  491. //
  492. LRESULT
  493. CAdvancedDlg::List_OnCommand(
  494. WORD wCtlIn
  495. , WORD wCodeIn
  496. , LPARAM lParam
  497. )
  498. {
  499. TraceFunc( "" );
  500. LRESULT lr = FALSE;
  501. switch ( wCtlIn )
  502. {
  503. case IDC_INPLACEEDIT:
  504. if ( EN_KILLFOCUS == wCodeIn || CBN_KILLFOCUS == wCodeIn )
  505. {
  506. if ( NULL != _pEdit )
  507. {
  508. STHR( PersistControlInProperty( ) );
  509. _pEdit->Release( );
  510. _pEdit = NULL;
  511. }
  512. }
  513. break;
  514. }
  515. lr = DefSubclassProc( _hwndList, WM_COMMAND, MAKEWPARAM( wCtlIn, wCodeIn ), lParam );
  516. RETURN( lr );
  517. }
  518. //
  519. // WM_CHAR handler for ListView Subclass
  520. //
  521. LRESULT
  522. CAdvancedDlg::List_OnChar(
  523. UINT uKeyCodeIn
  524. , LPARAM lParam
  525. )
  526. {
  527. TraceFunc( "" );
  528. HRESULT hr;
  529. LRESULT lr = FALSE;
  530. #if 0
  531. SHORT sRepeatCount = ( lParam & 0xFFFF );
  532. SHORT sScanCode = ( lParam & 0xF0000 ) >> 16;
  533. BOOL fExtended = ( lParam & 0x100000 ) != 0;
  534. BOOL fContext = ( lParam & 0x40000000 ) != 0;
  535. BOOL fTransition = ( lParam & 0x80000000 ) != 0;
  536. #endif
  537. INT iItem = ListView_GetSelectionMark( _hwndList );
  538. if ( -1 == iItem )
  539. return DefSubclassProc( _hwndList, WM_KEYDOWN, uKeyCodeIn, lParam );
  540. hr = STHR( CreateControlForProperty( iItem ) );
  541. if ( S_OK == hr )
  542. {
  543. HWND hwnd = GetFocus( );
  544. if ( _hwndList != hwnd )
  545. {
  546. lr = SendMessage( hwnd, WM_CHAR, (WPARAM) uKeyCodeIn, lParam );
  547. }
  548. }
  549. RETURN( lr );
  550. }
  551. //
  552. // WM_KEYDOWN handler for ListView Subclass
  553. //
  554. LRESULT
  555. CAdvancedDlg::List_OnKeyDown(
  556. UINT uKeyCodeIn
  557. , LPARAM lParam
  558. )
  559. {
  560. TraceFunc( "" );
  561. LRESULT lr = FALSE;
  562. #if 0
  563. SHORT sRepeatCount = ( lParam & 0xFFFF );
  564. SHORT sScanCode = ( lParam & 0xF0000 ) >> 16;
  565. BOOL fExtended = ( lParam & 0x100000 ) != 0;
  566. BOOL fContext = ( lParam & 0x40000000 ) != 0;
  567. BOOL fTransition = ( lParam & 0x80000000 ) != 0;
  568. #endif
  569. switch ( uKeyCodeIn )
  570. {
  571. case VK_F2:
  572. {
  573. INT iItem = ListView_GetSelectionMark( _hwndList );
  574. if ( -1 != iItem )
  575. {
  576. STHR( CreateControlForProperty( iItem ) );
  577. }
  578. }
  579. // fall thru
  580. default:
  581. lr = DefSubclassProc( _hwndList, WM_KEYDOWN, (WPARAM) uKeyCodeIn, lParam );
  582. break;
  583. }
  584. RETURN( lr );
  585. }
  586. //
  587. // WM_VSCROLL handler
  588. //
  589. LRESULT
  590. CAdvancedDlg::List_OnVertScroll(
  591. WORD wCodeIn
  592. , WORD wPosIn
  593. , HWND hwndFromIn
  594. )
  595. {
  596. TraceFunc( "" );
  597. //
  598. // Cancel any editting that's going on. This matches the behavior of
  599. // DefView.
  600. //
  601. if ( NULL != _pEdit )
  602. {
  603. _pEdit->Release( );
  604. _pEdit = NULL;
  605. }
  606. LRESULT lr = DefSubclassProc( _hwndList, WM_VSCROLL, MAKEWPARAM( wCodeIn, wPosIn ), (LPARAM) hwndFromIn );
  607. RETURN( lr );
  608. }
  609. //
  610. // WM_HCSCROLL handler
  611. //
  612. LRESULT
  613. CAdvancedDlg::List_OnHornScroll(
  614. WORD wCodeIn
  615. , WORD wPosIn
  616. , HWND hwndFromIn
  617. )
  618. {
  619. TraceFunc( "" );
  620. //
  621. // Cancel any editting that's going on. This matches the behavior of
  622. // DefView.
  623. //
  624. if ( NULL != _pEdit )
  625. {
  626. _pEdit->Release( );
  627. _pEdit = NULL;
  628. }
  629. LRESULT lr = DefSubclassProc( _hwndList, WM_HSCROLL, MAKEWPARAM( wCodeIn, wPosIn ), (LPARAM) hwndFromIn );
  630. RETURN( lr );
  631. }
  632. //
  633. // WM_DESTROY handler
  634. //
  635. LRESULT
  636. CAdvancedDlg::OnDestroy( void )
  637. {
  638. TraceFunc( "" );
  639. LRESULT lr = FALSE;
  640. RETURN( lr );
  641. }
  642. //
  643. // Description:
  644. // Creates and initializes the control to edit the property selected.
  645. //
  646. // Return Values:
  647. // S_OK
  648. // Successfully created and initialized control.
  649. //
  650. // S_FALSE
  651. // Read-only property - no control created.
  652. //
  653. // E_FAIL
  654. // Failed to create control.
  655. //
  656. // other HRESULTs
  657. //
  658. HRESULT
  659. CAdvancedDlg::CreateControlForProperty(
  660. INT iItemIn
  661. )
  662. {
  663. TraceFunc( "" );
  664. HRESULT hr;
  665. BOOL bRet;
  666. CLSID clsidControl;
  667. RECT rectItem;
  668. RECT rectList;
  669. UINT uCodePage;
  670. LVITEM lvi;
  671. DEFVAL * pDefVals;
  672. int iImage;
  673. PROPVARIANT * ppropvar;
  674. IPropertyUI * ppui = NULL;
  675. lvi.iItem = iItemIn;
  676. lvi.mask = LVIF_PARAM;
  677. lvi.iSubItem = 0;
  678. bRet = TBOOL( ListView_GetItem( _hwndList, &lvi ) );
  679. if ( !bRet )
  680. goto ControlFailed;
  681. _pItem = (CPropertyCacheItem *) lvi.lParam;
  682. AssertMsg( NULL != _pItem, "Programming error - how did this item get added?" );
  683. hr = THR( _pItem->GetImageIndex( &iImage ) );
  684. if ( S_OK != hr )
  685. goto Cleanup;
  686. //
  687. // Don't invoke the "Edit control" if the property is read-only.
  688. //
  689. if ( PTI_PROP_READONLY == iImage )
  690. {
  691. hr = S_FALSE;
  692. goto Cleanup;
  693. }
  694. hr = STHR( _pItem->GetControlCLSID( &clsidControl ) );
  695. if ( S_OK != hr )
  696. goto Cleanup;
  697. hr = THR( _pItem->GetCodePage( &uCodePage ) );
  698. if ( FAILED( hr ) )
  699. goto Cleanup;
  700. hr = STHR( _pItem->GetPropertyUIHelper( &ppui ) );
  701. if ( S_OK != hr )
  702. goto Cleanup;
  703. hr = THR( _pItem->GetPropertyValue( &ppropvar ) );
  704. if ( FAILED( hr ) )
  705. goto Cleanup;
  706. hr = STHR( _pItem->GetStateStrings( &pDefVals ) );
  707. if ( FAILED( hr ) )
  708. goto Cleanup;
  709. Assert( NULL == _pEdit );
  710. hr = THR( CoCreateInstance( clsidControl, NULL, CLSCTX_INPROC, TYPESAFEPARAMS(_pEdit) ) );
  711. if ( FAILED( hr ) )
  712. goto Cleanup;
  713. bRet = TBOOL( ListView_GetSubItemRect( _hwndList, lvi.iItem, 1, LVIR_BOUNDS , &rectItem) );
  714. if ( !bRet )
  715. goto ControlFailed;
  716. //
  717. // Make sure the rect is only in the visible region of the list view.
  718. //
  719. bRet = TBOOL( GetWindowRect( _hwndList, &rectList ) );
  720. if ( !bRet )
  721. goto ControlFailed;
  722. if ( rectItem.right > rectList.right - rectList.left )
  723. {
  724. rectItem.right = rectList.right - rectList.left;
  725. }
  726. if ( rectItem.left < 0 )
  727. {
  728. rectItem.left = 0;
  729. }
  730. hr = THR( _pEdit->Initialize( _hwndList, uCodePage, &rectItem, ppui, ppropvar, pDefVals ) );
  731. if ( FAILED( hr ) )
  732. goto Cleanup;
  733. Cleanup:
  734. if ( NULL != ppui )
  735. {
  736. ppui->Release( );
  737. }
  738. HRETURN( hr );
  739. ControlFailed:
  740. hr = THR( E_FAIL );
  741. goto Cleanup;
  742. }
  743. //
  744. // Description:
  745. // Informs the control, _pEdit, to persist its value into the variant.
  746. //
  747. // Return Value:
  748. // S_OK
  749. // Success! Property value updated.
  750. //
  751. // S_FALSE
  752. // _pEdit was NULL.
  753. //
  754. // other HRESULTs.
  755. //
  756. HRESULT
  757. CAdvancedDlg::PersistControlInProperty( void )
  758. {
  759. TraceFunc( "" );
  760. HRESULT hr;
  761. LVITEM lvi;
  762. LVFINDINFO lvfi;
  763. VARTYPE vt;
  764. PROPVARIANT * ppropvar;
  765. if ( NULL == _pEdit )
  766. goto NoEditControlEditting;
  767. lvfi.flags = LVFI_PARAM;
  768. lvfi.lParam = (LPARAM) _pItem;
  769. lvfi.vkDirection = VK_DOWN;
  770. lvi.iItem = ListView_FindItem( _hwndList, -1, &lvfi );
  771. if ( -1 == lvi.iItem )
  772. goto NoEditControlEditting;
  773. hr = THR( _pItem->GetPropertyValue( &ppropvar ) );
  774. if ( FAILED( hr ) )
  775. goto Cleanup;
  776. switch( ppropvar->vt )
  777. {
  778. case VT_EMPTY:
  779. case VT_NULL:
  780. {
  781. hr = THR( _pItem->GetDefaultVarType( &vt ) );
  782. if ( FAILED( hr ) )
  783. goto Cleanup;
  784. }
  785. break;
  786. default:
  787. vt = ppropvar->vt;
  788. break;
  789. }
  790. PropVariantInit( ppropvar );
  791. hr = STHR( _pEdit->Persist( vt, ppropvar ) );
  792. if ( FAILED( hr ) )
  793. goto Cleanup;
  794. if ( S_OK == hr )
  795. {
  796. hr = THR( _pItem->MarkDirty( ) );
  797. if ( FAILED( hr ) )
  798. goto Cleanup;
  799. hr = THR( _pItem->GetPropertyStringValue( (LPCWSTR *) &lvi.pszText ) );
  800. if ( FAILED( hr ) )
  801. goto Cleanup;
  802. lvi.mask = LVIF_TEXT;
  803. lvi.iSubItem = 1;
  804. BOOL bRet = TBOOL( ListView_SetItem( _hwndList, &lvi ) );
  805. if ( !bRet )
  806. goto NoEditControlEditting;
  807. //
  808. // Tell the property sheet to activate the "Apply" button.
  809. //
  810. PropSheet_Changed( GetParent( _hwndParent ), _hwndParent );
  811. }
  812. Cleanup:
  813. HRETURN( hr );
  814. NoEditControlEditting:
  815. hr = THR( S_FALSE );
  816. goto Cleanup;
  817. }
  818. //
  819. // WM_HELP handler
  820. //
  821. LRESULT
  822. CAdvancedDlg::OnHelp(
  823. LPHELPINFO pHelpInfoIn
  824. )
  825. {
  826. TraceFunc( "" );
  827. LRESULT lr = FALSE;
  828. THR( DoHelp( (HWND) pHelpInfoIn->hItemHandle, pHelpInfoIn->MousePos.x, pHelpInfoIn->MousePos.y, HELP_WM_HELP ) );
  829. RETURN( lr );
  830. }
  831. //
  832. // WM_CONTEXTMENU handler
  833. //
  834. LRESULT
  835. CAdvancedDlg::OnContextMenu(
  836. HWND hwndIn
  837. , int iXIn
  838. , int iYIn
  839. )
  840. {
  841. TraceFunc( "" );
  842. LRESULT lr = FALSE;
  843. THR( DoHelp( hwndIn, iXIn, iYIn, HELP_CONTEXTMENU ) );
  844. RETURN( lr );
  845. }
  846. //
  847. // Description:
  848. // Handles locating the item within the list view and construct
  849. // a fake IDC to IDH to display the correct help text for the
  850. // item.
  851. //
  852. // Return Values:
  853. // S_OK
  854. // Success.
  855. //
  856. HRESULT
  857. CAdvancedDlg::DoHelp(
  858. HWND hwndIn
  859. , int iXIn
  860. , int iYIn
  861. , UINT uCommandIn
  862. )
  863. {
  864. TraceFunc( "" );
  865. HRESULT hr = S_OK;
  866. HWND hwndList = GetDlgItem( _hdlg, IDC_PROPERTIES );
  867. if ( hwndList == hwndIn )
  868. {
  869. BOOL bRet;
  870. HRESULT hr;
  871. int iItem;
  872. RECT rcList;
  873. LVITEM lvi;
  874. LPCWSTR pszHelpFile; // don't free
  875. UINT uHelpId;
  876. CPropertyCacheItem * pItem;
  877. LVHITTESTINFO lvhti;
  878. DWORD mapIDStoIDH[ ] = { IDC_PROPERTIES, 0, 0, 0 };
  879. bRet = TBOOL( GetWindowRect( hwndList, &rcList ) );
  880. if ( !bRet )
  881. goto Cleanup;
  882. lvhti.pt.x = iXIn - rcList.left;
  883. lvhti.pt.y = iYIn - rcList.top;
  884. lvhti.flags = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON;
  885. iItem = ListView_HitTest( hwndList, &lvhti );
  886. if ( -1 == iItem )
  887. goto Cleanup; // item not found.
  888. lvi.iItem = iItem;
  889. lvi.mask = LVIF_PARAM;
  890. lvi.iSubItem = 0;
  891. bRet = TBOOL( ListView_GetItem( _hwndList, &lvi ) );
  892. if ( !bRet )
  893. goto Cleanup;
  894. pItem = (CPropertyCacheItem *) lvi.lParam;
  895. AssertMsg( NULL != pItem, "Programming error - how did this item get added?" );
  896. hr = THR( pItem->GetPropertyHelpInfo( &pszHelpFile, &uHelpId ) );
  897. if ( FAILED( hr ) )
  898. goto Cleanup;
  899. mapIDStoIDH[ 1 ] = uHelpId;
  900. TBOOL( WinHelp( hwndIn, pszHelpFile, uCommandIn, (DWORD_PTR)(LPSTR) mapIDStoIDH ) );
  901. }
  902. Cleanup:
  903. HRETURN( hr );
  904. }
  905. // ***************************************************************************
  906. //
  907. // Public methods
  908. //
  909. // ***************************************************************************
  910. //
  911. // Description:
  912. // Hides the dialog.
  913. //
  914. // Return Value:
  915. // S_OK
  916. // Success!
  917. //
  918. HRESULT
  919. CAdvancedDlg::Hide( void )
  920. {
  921. TraceFunc( "" );
  922. HRESULT hr;
  923. ShowWindow( _hdlg, SW_HIDE );
  924. hr = S_OK;
  925. HRETURN( hr );
  926. }
  927. //
  928. // Description:
  929. // Shows the dialog.
  930. //
  931. // Return Values:
  932. // S_OK
  933. // Success!
  934. //
  935. HRESULT
  936. CAdvancedDlg::Show( void )
  937. {
  938. TraceFunc( "" );
  939. HRESULT hr = S_OK;
  940. ShowWindow( _hdlg, SW_SHOW );
  941. SetFocus( _hdlg );
  942. HRETURN( hr );
  943. }
  944. //
  945. // Description:
  946. // Populates the properties of the dialog.
  947. //
  948. // Return Values:
  949. // S_OK
  950. // Success!
  951. //
  952. // E_INVALIDARG
  953. // ppcIn is NULL.
  954. //
  955. // other HRESULTs.
  956. //
  957. HRESULT
  958. CAdvancedDlg::PopulateProperties(
  959. CPropertyCache * ppcIn
  960. , DWORD dwDocTypeIn
  961. , BOOL fMultipleIn
  962. )
  963. {
  964. TraceFunc( "" );
  965. HRESULT hr;
  966. RECT rect;
  967. LVCOLUMN lvc;
  968. BOOL bRet;
  969. LVITEM lvi;
  970. ULONG idxFolder;
  971. ULONG idxProperty;
  972. CPropertyCacheItem * pItem;
  973. int iItem = 0;
  974. //
  975. // Check parameters
  976. //
  977. if ( NULL == ppcIn )
  978. {
  979. ReplaceListViewWithString( IDS_NOPROPERTIES_CAPTION );
  980. hr = S_OK;
  981. goto Cleanup;
  982. }
  983. _fMultipleSources = fMultipleIn;
  984. //
  985. // Clear out the previous list view contents.
  986. //
  987. TBOOL( ListView_DeleteAllItems( _hwndList ) );
  988. //
  989. // See if we have any properties to show.
  990. //
  991. hr = STHR( ppcIn->GetNextItem( NULL, &pItem ) );
  992. if ( S_OK == hr )
  993. {
  994. //
  995. // Walk the default property list and add items that match this property
  996. // folder to listview.
  997. //
  998. // If the SHIFT key is down, all properties retrieved and added will be
  999. // shown (if possible).
  1000. //
  1001. for ( idxProperty = 0; NULL != g_rgDefPropertyItems[ idxProperty ].pszName; idxProperty ++ )
  1002. {
  1003. if ( !( g_rgDefPropertyItems[ idxProperty ].dwSrcType & dwDocTypeIn )
  1004. && !( GetKeyState( VK_SHIFT ) < 0 )
  1005. )
  1006. {
  1007. continue; // property doesn't apply
  1008. }
  1009. //
  1010. // Search the property cache for the entry.
  1011. //
  1012. hr = STHR( ppcIn->FindItemEntry( g_rgDefPropertyItems[ idxProperty ].pFmtID
  1013. , g_rgDefPropertyItems[ idxProperty ].propID
  1014. , &pItem
  1015. ) );
  1016. if ( S_OK != hr )
  1017. continue; // property not found... skip it
  1018. Assert ( NULL != pItem ); // paranoid
  1019. //
  1020. // Find the group that the property belongs too.
  1021. //
  1022. for ( idxFolder = 0; NULL != g_rgTopLevelFolders[ idxFolder ].pPFID; idxFolder ++ )
  1023. {
  1024. if ( *g_rgDefPropertyItems[ idxProperty ].ppfid == *g_rgTopLevelFolders[ idxFolder ].pPFID )
  1025. {
  1026. break;
  1027. }
  1028. }
  1029. AssertMsg( NULL != g_rgTopLevelFolders[ idxFolder ].pPFID, "Missing folder for listed property. Check DOCPROP.CPP." );
  1030. //
  1031. // Add the property name below the group
  1032. //
  1033. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE | LVIF_GROUPID;
  1034. lvi.iSubItem = 0;
  1035. lvi.iItem = iItem;
  1036. lvi.iGroupId = idxFolder;
  1037. lvi.lParam = (LPARAM) pItem;
  1038. hr = THR( pItem->GetImageIndex( &lvi.iImage ) );
  1039. if ( FAILED( hr ) )
  1040. {
  1041. lvi.iImage = 0;
  1042. }
  1043. else
  1044. {
  1045. if ( _fMultipleSources )
  1046. {
  1047. lvi.iImage += MULTIDOC_IMAGE_OFFSET_VALUE;
  1048. }
  1049. }
  1050. hr = THR( pItem->GetPropertyTitle( (LPCWSTR *) &lvi.pszText ) );
  1051. if ( FAILED( hr ) )
  1052. continue;
  1053. iItem = ListView_InsertItem( _hwndList, &lvi );
  1054. if ( -1 == iItem )
  1055. continue;
  1056. //
  1057. // Now add the property value.
  1058. //
  1059. lvi.mask = LVIF_TEXT;
  1060. lvi.iItem = iItem;
  1061. lvi.iSubItem = 1;
  1062. hr = THR( pItem->GetPropertyStringValue( (LPCWSTR *) &lvi.pszText ) );
  1063. if ( FAILED( hr ) )
  1064. continue;
  1065. bRet = TBOOL( ListView_SetItem( _hwndList, &lvi ) );
  1066. if ( !bRet )
  1067. continue;
  1068. iItem ++;
  1069. }
  1070. //
  1071. // Give the first item focus
  1072. //
  1073. ListView_SetItemState( _hwndList, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED );
  1074. }
  1075. if ( 0 == iItem )
  1076. {
  1077. if ( _fMultipleSources )
  1078. {
  1079. ReplaceListViewWithString( IDS_NOCOMMONS_CAPTION );
  1080. }
  1081. else
  1082. {
  1083. ReplaceListViewWithString( IDS_NOPROPERTIES_CAPTION );
  1084. }
  1085. }
  1086. //
  1087. // Auto-adjust the column widths making sure that the first column doesn't
  1088. // make itself too big.
  1089. //
  1090. TBOOL( ListView_SetColumnWidth( _hwndList, 0, LVSCW_AUTOSIZE_USEHEADER ) );
  1091. bRet = TBOOL( GetClientRect( _hwndList, &rect ) );
  1092. if ( bRet )
  1093. {
  1094. lvc.mask = LVCF_WIDTH;
  1095. bRet = TBOOL( ListView_GetColumn( _hwndList, 0, &lvc ) );
  1096. if ( bRet )
  1097. {
  1098. int iSize = rect.right / 2;
  1099. if ( lvc.cx > iSize )
  1100. {
  1101. TBOOL( ListView_SetColumnWidth( _hwndList, 0, iSize ) );
  1102. TBOOL( ListView_SetColumnWidth( _hwndList, 1, iSize ) );
  1103. }
  1104. else
  1105. {
  1106. TBOOL( ListView_SetColumnWidth( _hwndList, 1, rect.right - lvc.cx ) );
  1107. }
  1108. }
  1109. }
  1110. if ( !bRet )
  1111. {
  1112. TBOOL( ListView_SetColumnWidth( _hwndList, 1, LVSCW_AUTOSIZE_USEHEADER ) );
  1113. }
  1114. hr = S_OK;
  1115. Cleanup:
  1116. HRETURN( hr );
  1117. }
  1118. //
  1119. // Description:
  1120. // Hides the list view control and displays a STATIC window with
  1121. // the text found in the string resource idsIn.
  1122. //
  1123. void
  1124. CAdvancedDlg::ReplaceListViewWithString( int idsIn )
  1125. {
  1126. TraceFunc( "" );
  1127. int iRet;
  1128. RECT rc;
  1129. WCHAR szCaption[ 255 ]; // random
  1130. iRet = LoadString( g_hInstance, idsIn, szCaption, ARRAYSIZE(szCaption) );
  1131. AssertMsg( iRet, "Missing string resource?" );
  1132. ShowWindow( _hwndList, SW_HIDE );
  1133. TBOOL( GetWindowRect( _hwndList, &rc ) );
  1134. iRet = MapWindowRect( HWND_DESKTOP, _hdlg, &rc );
  1135. TBOOL( 0 != iRet );
  1136. HWND hwnd = CreateWindow( WC_STATIC
  1137. , szCaption
  1138. , WS_CHILD | WS_VISIBLE
  1139. , rc.left
  1140. , rc.top
  1141. , rc.right - rc.left
  1142. , rc.bottom - rc.top
  1143. , _hdlg
  1144. , (HMENU) -1
  1145. , g_hInstance
  1146. , NULL
  1147. );
  1148. TBOOL( NULL != hwnd );
  1149. HFONT hFont = (HFONT) SendMessage( _hdlg, WM_GETFONT, 0, 0 );
  1150. SendMessage( hwnd, WM_SETFONT, (WPARAM) hFont, 0 );
  1151. TraceFuncExit( );
  1152. }