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.

857 lines
16 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 "PropertyCacheItem.h"
  15. #include "PropertyCache.h"
  16. #include "SimpleDlg.h"
  17. #include "shutils.h"
  18. #include "WMUser.h"
  19. #include "PropVar.h"
  20. #pragma hdrstop
  21. DEFINE_THISCLASS( "CSimpleDlg" )
  22. //
  23. // Globals
  24. //
  25. #define SUMMARYPROP(s) { &FMTID_SummaryInformation, PIDSI_##s, IDC_##s }
  26. #define DOCSUMMARYPROP(s) { &FMTID_DocSummaryInformation, PIDDSI_##s, IDC_##s }
  27. const struct
  28. {
  29. const FMTID *pFmtId;
  30. PROPID propid;
  31. UINT idc;
  32. // could add VARTYPE if we did anything other than strings
  33. } g_rgBasicProps[] = {
  34. SUMMARYPROP(TITLE)
  35. , SUMMARYPROP(SUBJECT)
  36. , SUMMARYPROP(AUTHOR)
  37. , SUMMARYPROP(KEYWORDS)
  38. , SUMMARYPROP(COMMENTS)
  39. , DOCSUMMARYPROP(CATEGORY)
  40. };
  41. // ************************************************************************
  42. //
  43. // Constructor / Destructor
  44. //
  45. // ************************************************************************
  46. //
  47. //
  48. //
  49. HRESULT
  50. CSimpleDlg::CreateInstance(
  51. CSimpleDlg ** pSimDlgOut
  52. , HWND hwndParentIn
  53. , BOOL fMultipleIn
  54. )
  55. {
  56. TraceFunc( "" );
  57. HRESULT hr;
  58. Assert( NULL != pSimDlgOut );
  59. CSimpleDlg * pthis = new CSimpleDlg;
  60. if ( NULL != pthis )
  61. {
  62. hr = THR( pthis->Init( hwndParentIn, fMultipleIn ) );
  63. if ( SUCCEEDED( hr ) )
  64. {
  65. *pSimDlgOut = pthis;
  66. (*pSimDlgOut)->AddRef( );
  67. }
  68. pthis->Release( );
  69. }
  70. else
  71. {
  72. hr = E_OUTOFMEMORY;
  73. }
  74. HRETURN( hr );
  75. }
  76. //
  77. //
  78. //
  79. CSimpleDlg::CSimpleDlg( void )
  80. : _cRef( 1 )
  81. {
  82. TraceFunc( "" );
  83. Assert( 1 == _cRef );
  84. Assert( NULL == _hwndParent );
  85. Assert( NULL == _hdlg );
  86. Assert( FALSE == _fMultipleSources );
  87. Assert( FALSE == _fNoProperties );
  88. InterlockedIncrement( &g_cObjects );
  89. TraceFuncExit();
  90. }
  91. //
  92. //
  93. //
  94. HRESULT
  95. CSimpleDlg::Init(
  96. HWND hwndParentIn
  97. , BOOL fMultipleIn
  98. )
  99. {
  100. TraceFunc( "" );
  101. HRESULT hr = S_OK;
  102. _hwndParent = hwndParentIn;
  103. _fMultipleSources = fMultipleIn;
  104. // IUnknown stuff
  105. Assert( _cRef == 1 );
  106. //
  107. // Create the dialog
  108. //
  109. _hdlg = CreateDialogParam( g_hInstance
  110. , MAKEINTRESOURCE(IDD_SIMPLEVIEW)
  111. , _hwndParent
  112. , DlgProc
  113. , (LPARAM) this
  114. );
  115. if ( NULL == _hdlg )
  116. goto ErrorGLE;
  117. Cleanup:
  118. HRETURN( hr );
  119. ErrorGLE:
  120. {
  121. DWORD dwErr = TW32( GetLastError( ) );
  122. hr = HRESULT_FROM_WIN32( dwErr );
  123. }
  124. goto Cleanup;
  125. }
  126. //
  127. //
  128. //
  129. CSimpleDlg::~CSimpleDlg( )
  130. {
  131. TraceFunc( "" );
  132. if ( NULL != _hdlg )
  133. {
  134. DestroyWindow( _hdlg );
  135. }
  136. InterlockedDecrement( &g_cObjects );
  137. TraceFuncExit();
  138. }
  139. // ************************************************************************
  140. //
  141. // IUnknown
  142. //
  143. // ************************************************************************
  144. //
  145. //
  146. //
  147. STDMETHODIMP
  148. CSimpleDlg::QueryInterface(
  149. REFIID riid,
  150. LPVOID *ppv
  151. )
  152. {
  153. TraceQIFunc( riid, ppv );
  154. HRESULT hr = E_NOINTERFACE;
  155. if ( IsEqualIID( riid, __uuidof(IUnknown) ) )
  156. {
  157. *ppv = static_cast< IUnknown * >( this );
  158. hr = S_OK;
  159. }
  160. #if 0
  161. else if ( IsEqualIID( riid, __uuidof(IShellExtInit) ) )
  162. {
  163. *ppv = TraceInterface( __THISCLASS__, IShellExtInit, this, 0 );
  164. hr = S_OK;
  165. }
  166. #endif
  167. if ( SUCCEEDED( hr ) )
  168. {
  169. ((IUnknown*) *ppv)->AddRef( );
  170. }
  171. QIRETURN( hr, riid );
  172. }
  173. //
  174. //
  175. //
  176. STDMETHODIMP_(ULONG)
  177. CSimpleDlg::AddRef( void )
  178. {
  179. TraceFunc( "[IUnknown]" );
  180. _cRef ++; // apartment
  181. RETURN( _cRef );
  182. }
  183. //
  184. //
  185. //
  186. STDMETHODIMP_(ULONG)
  187. CSimpleDlg::Release( void )
  188. {
  189. TraceFunc( "[IUnknown]" );
  190. _cRef --; // apartment
  191. if ( 0 != _cRef )
  192. RETURN( _cRef );
  193. delete this;
  194. RETURN( 0 );
  195. }
  196. // ***************************************************************************
  197. //
  198. // Dialog Proc and Property Sheet Callback
  199. //
  200. // ***************************************************************************
  201. //
  202. //
  203. //
  204. INT_PTR CALLBACK
  205. CSimpleDlg::DlgProc(
  206. HWND hDlgIn
  207. , UINT uMsgIn
  208. , WPARAM wParam
  209. , LPARAM lParam
  210. )
  211. {
  212. // Don't do TraceFunc because every mouse movement will cause this function to be called.
  213. WndMsg( hDlgIn, uMsgIn, wParam, lParam );
  214. LRESULT lr = FALSE;
  215. CSimpleDlg * pPage = (CSimpleDlg *) GetWindowLongPtr( hDlgIn, DWLP_USER );
  216. if ( uMsgIn == WM_INITDIALOG )
  217. {
  218. SetWindowLongPtr( hDlgIn, DWLP_USER, lParam );
  219. pPage = (CSimpleDlg *) lParam ;
  220. pPage->_hdlg = hDlgIn;
  221. }
  222. if ( pPage != NULL )
  223. {
  224. Assert( hDlgIn == pPage->_hdlg );
  225. switch( uMsgIn )
  226. {
  227. case WM_INITDIALOG:
  228. lr = pPage->OnInitDialog( );
  229. break;
  230. case WM_COMMAND:
  231. lr = pPage->OnCommand( HIWORD(wParam), LOWORD(wParam), lParam );
  232. break;
  233. case WM_NOTIFY:
  234. lr = pPage->OnNotify( (int) wParam, (LPNMHDR) lParam );
  235. break;
  236. case WM_DESTROY:
  237. SetWindowLongPtr( hDlgIn, DWLP_USER, NULL );
  238. lr = pPage->OnDestroy( );
  239. break;
  240. case WM_HELP:
  241. lr = pPage->OnHelp( (LPHELPINFO) lParam );
  242. break;
  243. case WM_CONTEXTMENU:
  244. lr = pPage->OnContextMenu( (HWND) wParam, LOWORD(lParam), HIWORD(lParam) );
  245. break;
  246. }
  247. }
  248. return lr;
  249. }
  250. // ***************************************************************************
  251. //
  252. // Private methods
  253. //
  254. // ***************************************************************************
  255. //
  256. // WM_INITDIALOG handler
  257. //
  258. LRESULT
  259. CSimpleDlg::OnInitDialog( void )
  260. {
  261. TraceFunc( "" );
  262. LRESULT lr = TRUE; // set focus
  263. Assert( NULL != _hdlg ); // this should have been initialized in the DlgProc.
  264. RETURN( lr );
  265. }
  266. //
  267. // WM_COMMAND handler
  268. //
  269. LRESULT
  270. CSimpleDlg::OnCommand(
  271. WORD wCodeIn
  272. , WORD wCtlIn
  273. , LPARAM lParam
  274. )
  275. {
  276. TraceFunc( "" );
  277. LRESULT lr = FALSE;
  278. switch( wCtlIn )
  279. {
  280. case IDC_ADVANCED:
  281. if ( BN_CLICKED == wCodeIn )
  282. {
  283. THR( (HRESULT) SendMessage( _hwndParent, WMU_TOGGLE, 0, 0 ) );
  284. }
  285. break;
  286. case IDC_TITLE:
  287. case IDC_SUBJECT:
  288. case IDC_AUTHOR:
  289. case IDC_CATEGORY:
  290. case IDC_KEYWORDS:
  291. case IDC_COMMENTS:
  292. if ( EN_CHANGE == wCodeIn )
  293. {
  294. PropSheet_Changed( GetParent( _hwndParent ), _hwndParent );
  295. }
  296. else if ( EN_KILLFOCUS == wCodeIn )
  297. {
  298. STHR( PersistControlInProperty( wCtlIn ) );
  299. }
  300. break;
  301. }
  302. RETURN( lr );
  303. }
  304. //
  305. // WM_NOTIFY handler
  306. //
  307. LRESULT
  308. CSimpleDlg::OnNotify(
  309. int iCtlIdIn
  310. , LPNMHDR pnmhIn
  311. )
  312. {
  313. TraceFunc( "" );
  314. LRESULT lr = FALSE;
  315. #if 0
  316. switch( pnmhIn->code )
  317. {
  318. default:
  319. break;
  320. }
  321. #endif
  322. RETURN( lr );
  323. }
  324. //
  325. // WM_DESTROY handler
  326. //
  327. LRESULT
  328. CSimpleDlg::OnDestroy( void )
  329. {
  330. TraceFunc( "" );
  331. LRESULT lr = FALSE;
  332. RETURN( lr );
  333. }
  334. //
  335. // Description:
  336. // Stores the "basic" properties into the prop variant.
  337. //
  338. // Return Values:
  339. // S_OK
  340. // Success!
  341. //
  342. // other HRESULTs.
  343. //
  344. HRESULT
  345. CSimpleDlg::PersistProperties( void )
  346. {
  347. TraceFunc( "" );
  348. HRESULT hr;
  349. ULONG idx;
  350. //
  351. // Loop the the properties updating the dialog as we go.
  352. //
  353. for ( idx = 0; idx < ARRAYSIZE(g_rgBasicProps); idx ++ )
  354. {
  355. hr = STHR( PersistControlInProperty( g_rgBasicProps[ idx ].idc ) );
  356. if ( FAILED( hr ) )
  357. goto Cleanup;
  358. }
  359. hr = S_OK;
  360. Cleanup:
  361. HRETURN( hr );
  362. }
  363. //
  364. // Description:
  365. // Stores the current value of a control into the property cache.
  366. //
  367. // Return Values:
  368. // S_OK
  369. // Success!
  370. //
  371. // S_FALSE
  372. // Nothing to save.
  373. //
  374. // E_FAIL
  375. // Property could not be persisted.
  376. //
  377. // E_OUTOFMEMORY
  378. // OutOfMemory
  379. //
  380. // other HRESULTs.
  381. //
  382. HRESULT
  383. CSimpleDlg::PersistControlInProperty(
  384. UINT uCtlIdIn
  385. )
  386. {
  387. TraceFunc( "" );
  388. HRESULT hr;
  389. int iLen;
  390. int iRet;
  391. HWND hwndCtl;
  392. UINT uCodePage;
  393. VARTYPE vt;
  394. CPropertyCacheItem * pItem;
  395. PROPVARIANT * ppropvar;
  396. LPWSTR pszBuf = NULL;
  397. hwndCtl = GetDlgItem( _hdlg, uCtlIdIn );
  398. if ( NULL == hwndCtl )
  399. goto ErrorPersistingValue;
  400. pItem = (CPropertyCacheItem *) GetWindowLongPtr( hwndCtl, GWLP_USERDATA );
  401. if ( NULL == pItem )
  402. {
  403. hr = S_FALSE;
  404. goto Cleanup;
  405. }
  406. hr = THR( pItem->GetCodePage( &uCodePage ) );
  407. if ( FAILED( hr ) )
  408. goto Cleanup;
  409. hr = THR( pItem->GetPropertyValue( &ppropvar ) );
  410. if ( FAILED( hr ) )
  411. goto Cleanup;
  412. switch ( ppropvar->vt )
  413. {
  414. case VT_EMPTY:
  415. case VT_NULL:
  416. {
  417. PropVariantInit( ppropvar );
  418. hr = THR( pItem->GetDefaultVarType( &vt ) );
  419. if ( FAILED( hr ) )
  420. goto Cleanup;
  421. }
  422. break;
  423. default:
  424. vt = ppropvar->vt;
  425. break;
  426. }
  427. iLen = GetWindowTextLength( hwndCtl );
  428. if ( iLen == 0 )
  429. {
  430. //
  431. // If nothing to get, then just clear the value and mark it dirty.
  432. //
  433. hr = THR( PropVariantClear( ppropvar ) );
  434. if ( FAILED( hr ) )
  435. goto Cleanup;
  436. hr = THR( pItem->MarkDirty( ) );
  437. goto Cleanup;
  438. }
  439. pszBuf = (LPWSTR) SysAllocStringLen( NULL, iLen );
  440. if ( NULL == pszBuf )
  441. goto OutOfMemory;
  442. iRet = GetWindowText( hwndCtl, pszBuf, iLen + 1 );
  443. Assert( iRet == iLen );
  444. hr = THR( PropVariantFromString( pszBuf, uCodePage, 0, vt, ppropvar ) );
  445. if ( FAILED( hr ) )
  446. goto Cleanup;
  447. hr = THR( pItem->MarkDirty( ) );
  448. if ( FAILED( hr ) )
  449. goto Cleanup;
  450. Cleanup:
  451. if ( NULL != pszBuf )
  452. {
  453. SysFreeString( pszBuf );
  454. }
  455. HRETURN( hr );
  456. OutOfMemory:
  457. hr = E_OUTOFMEMORY;
  458. goto Cleanup;
  459. ErrorPersistingValue:
  460. hr = THR( E_FAIL );
  461. goto Cleanup;
  462. }
  463. //
  464. // WM_HELP handler
  465. //
  466. LRESULT
  467. CSimpleDlg::OnHelp(
  468. LPHELPINFO pHelpInfoIn
  469. )
  470. {
  471. TraceFunc( "" );
  472. LRESULT lr = FALSE;
  473. THR( DoHelp( (HWND) pHelpInfoIn->hItemHandle, pHelpInfoIn->MousePos.x, pHelpInfoIn->MousePos.y, HELP_WM_HELP ) );
  474. RETURN( lr );
  475. }
  476. //
  477. // WM_CONTEXTMENU handler
  478. //
  479. LRESULT
  480. CSimpleDlg::OnContextMenu(
  481. HWND hwndIn
  482. , int iXIn
  483. , int iYIn
  484. )
  485. {
  486. TraceFunc( "" );
  487. LRESULT lr = FALSE;
  488. THR( DoHelp( hwndIn, iXIn, iYIn, HELP_CONTEXTMENU ) );
  489. RETURN( lr );
  490. }
  491. //
  492. // Description:
  493. // Handles locating the item within the list view and construct
  494. // a fake IDC to IDH to display the correct help text for the
  495. // item.
  496. //
  497. // Return Values:
  498. // S_OK
  499. // Success.
  500. //
  501. HRESULT
  502. CSimpleDlg::DoHelp(
  503. HWND hwndIn
  504. , int iXIn
  505. , int iYIn
  506. , UINT uCommandIn
  507. )
  508. {
  509. TraceFunc( "" );
  510. ULONG idx;
  511. HRESULT hr = S_OK;
  512. for ( idx = 0; idx < ARRAYSIZE(g_rgBasicProps); idx ++ )
  513. {
  514. HWND hwndCtl = GetDlgItem( _hdlg, g_rgBasicProps[ idx ].idc );
  515. AssertMsg( NULL != hwndCtl, "Missing control or table is out of date!" );
  516. if ( hwndCtl == hwndIn )
  517. {
  518. CPropertyCacheItem * pItem;
  519. pItem = (CPropertyCacheItem *) GetWindowLongPtr( hwndCtl, GWLP_USERDATA );
  520. if ( NULL != pItem )
  521. {
  522. LPCWSTR pszHelpFile; // don't free
  523. UINT uHelpId;
  524. DWORD mapIDStoIDH[ ] = { 0, 0, 0, 0 };
  525. hr = THR( pItem->GetPropertyHelpInfo( &pszHelpFile, &uHelpId ) );
  526. if ( FAILED( hr ) )
  527. goto Cleanup;
  528. mapIDStoIDH[ 0 ] = g_rgBasicProps[ idx ].idc;
  529. mapIDStoIDH[ 1 ] = uHelpId;
  530. TBOOL( WinHelp( hwndIn, pszHelpFile, uCommandIn, (DWORD_PTR)(LPSTR) mapIDStoIDH ) );
  531. }
  532. }
  533. }
  534. Cleanup:
  535. HRETURN( hr );
  536. }
  537. // ***************************************************************************
  538. //
  539. // Public methods
  540. //
  541. // ***************************************************************************
  542. //
  543. // Description:
  544. // Hides the dialog.
  545. //
  546. // Return Value:
  547. // S_OK
  548. // Success!
  549. //
  550. HRESULT
  551. CSimpleDlg::Hide( void )
  552. {
  553. TraceFunc( "" );
  554. HRESULT hr;
  555. ShowWindow( _hdlg, SW_HIDE );
  556. hr = S_OK;
  557. HRETURN( hr );
  558. }
  559. //
  560. // Description:
  561. // Shows the dialog.
  562. //
  563. // Return Values:
  564. // S_OK
  565. // Success!
  566. //
  567. // S_FALSE
  568. // Success, but there isn't anything useful to display to the user.
  569. // One might flip to the Advanced dialog if possible (and the user
  570. // didn't ask to go to the Simple dialog).
  571. //
  572. HRESULT
  573. CSimpleDlg::Show( void )
  574. {
  575. TraceFunc( "" );
  576. HRESULT hr = S_OK;
  577. ShowWindow( _hdlg, SW_SHOW );
  578. SetFocus( _hdlg );
  579. if ( _fNoProperties )
  580. {
  581. hr = S_FALSE;
  582. }
  583. HRETURN( hr );
  584. }
  585. //
  586. // Description:
  587. // Populates the properties of the dialog.
  588. //
  589. // Return Values:
  590. // S_OK
  591. // Success!
  592. //
  593. // E_INVALIDARG
  594. // ppcIn is NULL.
  595. //
  596. // other HRESULTs.
  597. //
  598. HRESULT
  599. CSimpleDlg::PopulateProperties(
  600. CPropertyCache * ppcIn
  601. , DWORD dwDocTypeIn
  602. , BOOL fMultipleIn
  603. )
  604. {
  605. TraceFunc( "" );
  606. HRESULT hr;
  607. ULONG idx;
  608. LPCWSTR pcszValue;
  609. CPropertyCacheItem * pItem;
  610. static const WCHAR s_cszNULL[] = L"";
  611. //
  612. // Check parameters
  613. //
  614. if ( NULL == ppcIn )
  615. goto InvalidArg;
  616. //
  617. // Loop the the properties updating the dialog as we go.
  618. //
  619. _fNoProperties = TRUE;
  620. for ( idx = 0; idx < ARRAYSIZE(g_rgBasicProps); idx ++ )
  621. {
  622. HWND hwndCtl = GetDlgItem( _hdlg, g_rgBasicProps[ idx ].idc );
  623. AssertMsg( NULL != hwndCtl, "Missing control or table is out of date!" );
  624. //
  625. // Search the property cache for the entry.
  626. //
  627. hr = STHR( ppcIn->FindItemEntry( g_rgBasicProps[ idx ].pFmtId
  628. , g_rgBasicProps[ idx ].propid
  629. , &pItem
  630. ) );
  631. if ( S_OK == hr )
  632. {
  633. int iImage;
  634. Assert ( NULL != pItem ); // paranoid
  635. //
  636. // Retrieve the string value.
  637. //
  638. hr = THR( pItem->GetPropertyStringValue( &pcszValue ) );
  639. if ( S_OK != hr )
  640. goto ControlFailure;
  641. if ( NULL == pcszValue )
  642. {
  643. pcszValue = s_cszNULL;
  644. }
  645. //
  646. // Update the control.
  647. //
  648. SetWindowText( hwndCtl, pcszValue );
  649. SetWindowLongPtr( hwndCtl, GWLP_USERDATA, (LPARAM) pItem );
  650. _fNoProperties = FALSE;
  651. //
  652. // If the property is read-only, change the edit control to match.
  653. //
  654. hr = THR( pItem->GetImageIndex( &iImage ) );
  655. if ( S_OK != hr )
  656. goto ControlFailure;
  657. if ( PTI_PROP_READONLY == iImage )
  658. {
  659. EnableWindow( hwndCtl, FALSE );
  660. }
  661. //
  662. // If the control has mutliple values, mark it read-only. They can edit
  663. // it in the "Advanced" view and this would be an advanced operation.
  664. //
  665. if ( _fMultipleSources )
  666. {
  667. EnableWindow( hwndCtl, FALSE );
  668. }
  669. }
  670. else
  671. {
  672. ControlFailure:
  673. //
  674. // No equivalent property was found or there is an error in the
  675. // property set. Clear and disable the control.
  676. //
  677. SetWindowText( hwndCtl, s_cszNULL );
  678. EnableWindow( hwndCtl, FALSE );
  679. }
  680. }
  681. hr = S_OK;
  682. Cleanup:
  683. HRETURN( hr );
  684. InvalidArg:
  685. hr = THR( E_INVALIDARG );
  686. goto Cleanup;
  687. }