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.

857 lines
19 KiB

  1. //
  2. // Microsoft Windows Media Technologies
  3. // Copyright (C) Microsoft Corporation, 1999 - 2001. All rights reserved.
  4. //
  5. //
  6. // This workspace contains two projects -
  7. // 1. ProgHelp which implements the Progress Interface
  8. // 2. The Sample application WmdmApp.
  9. //
  10. // ProgHelp.dll needs to be registered first for the SampleApp to run.
  11. // Includes
  12. //
  13. #include "appPCH.h"
  14. // Local variables
  15. //
  16. // Constants
  17. //
  18. #define MIN_DEVICEWND_W 200
  19. // Macros
  20. //
  21. // Local functions
  22. //
  23. INT_PTR CALLBACK Device_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  24. /////////////////////////////////////////////////////////////////////
  25. //
  26. // Function implementations
  27. //
  28. CDevices::CDevices()
  29. {
  30. m_hwndDevices = NULL;
  31. m_hwndDevices_TV = NULL;
  32. m_himlSmall = NULL;
  33. }
  34. CDevices::~CDevices()
  35. {
  36. }
  37. HWND CDevices::GetHwnd( void )
  38. {
  39. return m_hwndDevices;
  40. }
  41. HWND CDevices::GetHwnd_TV( void )
  42. {
  43. return m_hwndDevices_TV;
  44. }
  45. BOOL CDevices::Create( HWND hwndParent )
  46. {
  47. BOOL fRet = FALSE;
  48. // Create the Devices dialog
  49. //
  50. m_hwndDevices = CreateDialogParam(
  51. g_hInst,
  52. MAKEINTRESOURCE( IDD_DEVICES ),
  53. hwndParent,
  54. Device_DlgProc,
  55. (LPARAM)this
  56. );
  57. ExitOnNull( m_hwndDevices );
  58. m_hwndDevices_TV = GetDlgItem( m_hwndDevices, IDC_LV_DEVICES );
  59. // Initialize image list
  60. //
  61. ExitOnFalse( InitImageList() );
  62. // Show the window
  63. //
  64. ShowWindow( m_hwndDevices, SW_SHOW );
  65. fRet = TRUE;
  66. lExit:
  67. return fRet;
  68. }
  69. VOID CDevices::Destroy( void )
  70. {
  71. RemoveAllItems();
  72. if( m_hwndDevices )
  73. {
  74. DestroyWindow( m_hwndDevices );
  75. }
  76. if( m_himlSmall )
  77. {
  78. ImageList_Destroy( m_himlSmall );
  79. }
  80. }
  81. VOID CDevices::OnSize( LPRECT prcMain )
  82. {
  83. INT nW, nH;
  84. nW = max( (prcMain->right - prcMain->left)/4, MIN_DEVICEWND_W );
  85. nH = prcMain->bottom - prcMain->top;
  86. SetWindowPos( m_hwndDevices, NULL, -4, 0, nW, nH, SWP_NOZORDER );
  87. SetWindowPos( m_hwndDevices_TV, NULL, 0, 0, nW-10, nH-27, SWP_NOZORDER );
  88. }
  89. BOOL CDevices::InitImageList( void )
  90. {
  91. BOOL fRet = FALSE;
  92. HICON hIcon;
  93. // Init Small image list
  94. //
  95. m_himlSmall = ImageList_Create(
  96. GetSystemMetrics(SM_CXSMICON),
  97. GetSystemMetrics(SM_CYSMICON),
  98. ILC_COLOR32 | ILC_MASK,
  99. -1, 0
  100. );
  101. ExitOnNull( m_himlSmall );
  102. // Load icons and add them to the image list
  103. //
  104. hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE(IDI_DEVICE) );
  105. if( hIcon != NULL )
  106. {
  107. ImageList_AddIcon( m_himlSmall, hIcon );
  108. }
  109. // Add the shell folder icons to the image lsit
  110. //
  111. {
  112. CHAR szWinPath[MAX_PATH+1];
  113. SHFILEINFO si;
  114. UINT nRet;
  115. nRet = GetWindowsDirectory( szWinPath, sizeof(szWinPath)/sizeof(szWinPath[0]) );
  116. if (nRet > 0 && nRet <= sizeof(szWinPath)/sizeof(szWinPath[0]))
  117. {
  118. SHGetFileInfo( szWinPath, 0, &si, sizeof(si), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_ICON );
  119. hIcon = si.hIcon;
  120. ImageList_AddIcon( m_himlSmall, hIcon );
  121. SHGetFileInfo( szWinPath, 0, &si, sizeof(si), SHGFI_SMALLICON | SHGFI_ICON | SHGFI_OPENICON );
  122. hIcon = si.hIcon;
  123. ImageList_AddIcon( m_himlSmall, hIcon );
  124. }
  125. else
  126. {
  127. // @@@@ Do we bail out or is ok to go on?
  128. // goto lExit;
  129. }
  130. }
  131. // Set the image list for the tree view
  132. //
  133. TreeView_SetImageList( m_hwndDevices_TV, m_himlSmall, TVSIL_NORMAL );
  134. // Everything went Ok
  135. //
  136. fRet = TRUE;
  137. lExit:
  138. return fRet;
  139. }
  140. VOID CDevices::RemoveAllItems( void )
  141. {
  142. HTREEITEM hItem;
  143. // Get Root item
  144. //
  145. hItem = TreeView_GetRoot( m_hwndDevices_TV );
  146. if( hItem )
  147. {
  148. do
  149. {
  150. // Remove all children of this device
  151. //
  152. INT nChildren = RemoveChildren( hItem );
  153. // Get the device class associated with this item
  154. //
  155. CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hItem );
  156. // Release device class
  157. //
  158. if( pItemData )
  159. {
  160. delete pItemData;
  161. TreeView_SetLParam( m_hwndDevices_TV, hItem, (LPARAM)NULL );
  162. }
  163. hItem = TreeView_GetNextSibling( m_hwndDevices_TV, hItem );
  164. } while( hItem != NULL );
  165. }
  166. // Then delete all the items from the list
  167. //
  168. TreeView_DeleteAllItems( m_hwndDevices_TV );
  169. }
  170. INT CDevices::RemoveChildren( HTREEITEM hItem )
  171. {
  172. BOOL nChildren = 0;
  173. HTREEITEM hNextItem;
  174. hNextItem = TreeView_GetChild( m_hwndDevices_TV, hItem );
  175. if( hNextItem )
  176. {
  177. do
  178. {
  179. nChildren++;
  180. // Remove all children of this device
  181. //
  182. nChildren += RemoveChildren( hNextItem );
  183. // Get the storage class associated with this item
  184. //
  185. CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hNextItem );
  186. // Release storage class
  187. //
  188. if( pItemData )
  189. {
  190. delete pItemData;
  191. TreeView_SetLParam( m_hwndDevices_TV, hNextItem, (LPARAM)NULL );
  192. }
  193. hNextItem = TreeView_GetNextSibling( m_hwndDevices_TV, hNextItem );
  194. } while( hNextItem != NULL );
  195. }
  196. return nChildren;
  197. }
  198. BOOL CDevices::AddItem( CItemData *pItemData )
  199. {
  200. BOOL fRet = TRUE;
  201. HTREEITEM hItem;
  202. TVINSERTSTRUCT tvis;
  203. // Set up the item information
  204. //
  205. tvis.hParent = TVI_ROOT;
  206. tvis.hInsertAfter = TVI_SORT;
  207. tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_CHILDREN;
  208. tvis.item.pszText = pItemData->m_szName;
  209. tvis.item.iImage = I_IMAGECALLBACK;
  210. tvis.item.iSelectedImage = I_IMAGECALLBACK;
  211. tvis.item.lParam = (LPARAM)pItemData;
  212. tvis.item.cChildren = 0;
  213. // Add the item
  214. //
  215. hItem = TreeView_InsertItem( m_hwndDevices_TV, &tvis );
  216. if( NULL == hItem )
  217. {
  218. return FALSE;
  219. }
  220. // If there are children, update the item
  221. //
  222. if( HasSubFolders(hItem) )
  223. {
  224. tvis.item.mask = TVIF_HANDLE | TVIF_CHILDREN;
  225. tvis.item.hItem = hItem;
  226. tvis.item.cChildren = 1;
  227. TreeView_SetItem( m_hwndDevices_TV, &(tvis.item) );
  228. }
  229. return fRet;
  230. }
  231. INT CDevices::AddChildren( HTREEITEM hItem, BOOL fDeviceItem )
  232. {
  233. INT nChildren = 0;
  234. HRESULT hr;
  235. IWMDMEnumStorage *pEnumStorage;
  236. // Get the storage enumerator associated with the hItem and
  237. //
  238. CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hItem );
  239. ExitOnNull( pItemData );
  240. pEnumStorage = pItemData->m_pEnumStorage;
  241. ExitOnNull( pEnumStorage );
  242. // Reset the storage enumerator
  243. //
  244. hr = pEnumStorage->Reset();
  245. ExitOnFail( hr );
  246. // Add the appropriate list of files to the ListView
  247. //
  248. while( TRUE )
  249. {
  250. IWMDMStorage *pWmdmStorage;
  251. CItemData *pItemStorage;
  252. ULONG ulFetched;
  253. hr = pEnumStorage->Next( 1, &pWmdmStorage, &ulFetched );
  254. if( hr != S_OK )
  255. {
  256. break;
  257. }
  258. if( ulFetched != 1 )
  259. {
  260. ExitOnFail( hr = E_UNEXPECTED );
  261. }
  262. pItemStorage = new CItemData;
  263. if( pItemStorage )
  264. {
  265. hr = pItemStorage->Init( pWmdmStorage );
  266. if( SUCCEEDED(hr) && pItemStorage->m_dwAttributes & WMDM_FILE_ATTR_FOLDER )
  267. {
  268. HTREEITEM hNewItem;
  269. TVINSERTSTRUCT tvis;
  270. // Set up the item information
  271. //
  272. tvis.hParent = hItem;
  273. tvis.hInsertAfter = TVI_SORT;
  274. tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_CHILDREN;
  275. tvis.item.pszText = pItemStorage->m_szName;
  276. tvis.item.iImage = I_IMAGECALLBACK;
  277. tvis.item.iSelectedImage = I_IMAGECALLBACK;
  278. tvis.item.lParam = (LPARAM)pItemStorage;
  279. tvis.item.cChildren = 0;
  280. // Add the item
  281. //
  282. hNewItem = TreeView_InsertItem( m_hwndDevices_TV, &tvis );
  283. if( hNewItem )
  284. {
  285. nChildren++;
  286. // If there are children, update the item
  287. //
  288. if( HasSubFolders(hNewItem) )
  289. {
  290. tvis.item.mask = TVIF_HANDLE | TVIF_CHILDREN;
  291. tvis.item.hItem = hNewItem;
  292. tvis.item.cChildren = 1;
  293. TreeView_SetItem( m_hwndDevices_TV, &(tvis.item) );
  294. }
  295. }
  296. else
  297. {
  298. delete pItemStorage;
  299. }
  300. }
  301. else
  302. {
  303. delete pItemStorage;
  304. }
  305. }
  306. pWmdmStorage->Release();
  307. }
  308. lExit:
  309. return nChildren;
  310. }
  311. BOOL CDevices::HasSubFolders( HTREEITEM hItem )
  312. {
  313. BOOL fRet = FALSE;
  314. // Get the storage enumeration interface from the item
  315. //
  316. CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hItem );
  317. ExitOnNull( pItemData );
  318. // If the item is a device or has the has-subfolders attribute set,
  319. // then return TRUE. Otherwise, return FALSE
  320. //
  321. if( pItemData->m_fIsDevice )
  322. {
  323. fRet = TRUE;
  324. }
  325. else if( pItemData->m_dwAttributes & WMDM_STORAGE_ATTR_HAS_FOLDERS )
  326. {
  327. fRet = TRUE;
  328. }
  329. else
  330. {
  331. fRet = FALSE;
  332. }
  333. lExit:
  334. return fRet;
  335. }
  336. HTREEITEM CDevices::GetSelectedItem( LPARAM *pLParam )
  337. {
  338. HTREEITEM hItem = TreeView_GetSelection( m_hwndDevices_TV );
  339. if( hItem )
  340. {
  341. // Return the lParam value of the item that is selected
  342. //
  343. if( pLParam )
  344. {
  345. *pLParam = TreeView_GetLParam( m_hwndDevices_TV, hItem );
  346. }
  347. }
  348. return hItem;
  349. }
  350. BOOL CDevices::SetSelectedItem( HTREEITEM hItem )
  351. {
  352. return TreeView_SelectItem( m_hwndDevices_TV, hItem );
  353. }
  354. BOOL CDevices::UpdateSelection( HTREEITEM hItem, BOOL fDirty )
  355. {
  356. BOOL fRet = FALSE;
  357. HRESULT hr;
  358. IWMDMEnumStorage *pEnumStorage = NULL;
  359. // If hItem is NULL, then use the currently-selected item.
  360. // If no item is selected, use the first device.
  361. //
  362. if( NULL == hItem )
  363. {
  364. hItem = GetSelectedItem( NULL );
  365. if( NULL == hItem )
  366. {
  367. hItem = TreeView_GetRoot( m_hwndDevices_TV );
  368. // If there are no devices, just exit
  369. //
  370. ExitOnNull( hItem );
  371. }
  372. }
  373. if( fDirty )
  374. {
  375. // Remove all current files
  376. //
  377. g_cDevFiles.RemoveAllItems();
  378. // Get the storage enumeration interface from the item
  379. //
  380. CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hItem );
  381. ExitOnNull( pItemData );
  382. pEnumStorage = pItemData->m_pEnumStorage;
  383. ExitOnNull( pEnumStorage );
  384. // Reset the storage enumerator
  385. //
  386. hr = pEnumStorage->Reset();
  387. ExitOnFail( hr );
  388. // Add the appropriate list of files to the ListView
  389. //
  390. while( TRUE )
  391. {
  392. IWMDMStorage *pWmdmStorage;
  393. CItemData *pItemStorage;
  394. ULONG ulFetched;
  395. hr = pEnumStorage->Next( 1, &pWmdmStorage, &ulFetched );
  396. if( hr != S_OK )
  397. {
  398. break;
  399. }
  400. if( ulFetched != 1 )
  401. {
  402. ExitOnFail( hr = E_UNEXPECTED );
  403. }
  404. pItemStorage = new CItemData;
  405. if( pItemStorage )
  406. {
  407. hr = pItemStorage->Init( pWmdmStorage );
  408. if( SUCCEEDED(hr) )
  409. {
  410. g_cDevFiles.AddItem( pItemStorage );
  411. }
  412. else
  413. {
  414. delete pItemStorage;
  415. }
  416. UiYield();
  417. }
  418. pWmdmStorage->Release();
  419. }
  420. SetSelectedItem( hItem );
  421. }
  422. // Update the device portion of the status bar
  423. //
  424. UpdateStatusBar();
  425. // Update the file portion of the status bar
  426. //
  427. g_cDevFiles.UpdateStatusBar();
  428. fRet = TRUE;
  429. lExit:
  430. return fRet;
  431. }
  432. INT CDevices::GetDeviceCount( VOID )
  433. {
  434. INT nCount = 0;
  435. HTREEITEM hItem;
  436. // Count Root items
  437. //
  438. for(
  439. hItem = TreeView_GetRoot( m_hwndDevices_TV );
  440. hItem != NULL;
  441. hItem = TreeView_GetNextSibling( m_hwndDevices_TV, hItem )
  442. )
  443. {
  444. nCount++;
  445. }
  446. return nCount;
  447. }
  448. CItemData *CDevices::GetRootDevice( HTREEITEM hItem )
  449. {
  450. HTREEITEM hRootItem;
  451. while( TRUE )
  452. {
  453. hRootItem = hItem;
  454. hItem = TreeView_GetParent( m_hwndDevices_TV, hRootItem );
  455. if( hItem == NULL )
  456. {
  457. break;
  458. }
  459. }
  460. return (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hRootItem );
  461. }
  462. VOID CDevices::UpdateStatusBar( VOID )
  463. {
  464. INT nCount;
  465. HRESULT hr;
  466. UINT uStrID;
  467. HTREEITEM hItem;
  468. CItemData *pItemDevice;
  469. DWORD dwMemUsed;
  470. char szSpaceKB[MAX_PATH];
  471. // Set the statusbar pane that shows the number of devices
  472. //
  473. nCount = GetDeviceCount();
  474. if( nCount == 0 )
  475. {
  476. uStrID = IDS_SB_DEVICE_MANY;
  477. }
  478. else if( nCount == 1 )
  479. {
  480. uStrID = IDS_SB_DEVICE_ONE;
  481. }
  482. else
  483. {
  484. uStrID = IDS_SB_DEVICE_MANY;
  485. }
  486. g_cStatus.SetTextFormatted( SB_PANE_DEVICE, uStrID, nCount, NULL );
  487. // If there is a selected device in the list, set the status for
  488. // the space free and used
  489. //
  490. hItem = GetSelectedItem( NULL );
  491. if( NULL == hItem )
  492. {
  493. // Empty the space used and free
  494. //
  495. g_cStatus.SetTextSz( SB_PANE_DEVFILES_USED, "" );
  496. g_cStatus.SetTextSz( SB_PANE_DEVFILES_FREE, "" );
  497. }
  498. else
  499. {
  500. pItemDevice = GetRootDevice( hItem );
  501. ExitOnNull( pItemDevice );
  502. hr = pItemDevice->Refresh();
  503. ExitOnFail( hr );
  504. dwMemUsed = pItemDevice->m_dwMemSizeKB - pItemDevice->m_dwMemFreeKB - pItemDevice->m_dwMemBadKB;
  505. // Set the space used
  506. //
  507. g_cStatus.SetTextFormatted(
  508. SB_PANE_DEVFILES_USED,
  509. IDS_SB_DEVICEFILES_USED,
  510. -1,
  511. FormatBytesToSz(dwMemUsed, 0, 1024, szSpaceKB, sizeof(szSpaceKB))
  512. );
  513. // Set the space free
  514. //
  515. g_cStatus.SetTextFormatted(
  516. SB_PANE_DEVFILES_FREE,
  517. IDS_SB_DEVICEFILES_FREE,
  518. -1,
  519. FormatBytesToSz(pItemDevice->m_dwMemFreeKB, 0, 1024, szSpaceKB, sizeof(szSpaceKB))
  520. );
  521. }
  522. lExit:
  523. return;
  524. }
  525. /////////////////////////////////////////////////////////////////////
  526. //
  527. // Local function implementations
  528. //
  529. INT_PTR CALLBACK Device_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  530. {
  531. WORD wId = LOWORD((DWORD)wParam);
  532. WORD wNotifyCode = HIWORD((DWORD)wParam);
  533. static CDevices *cDevices = NULL;
  534. static HWND hwndTV = NULL;
  535. static BOOL fSelChangeInProgress = FALSE;
  536. switch( uMsg )
  537. {
  538. case WM_INITDIALOG:
  539. cDevices = (CDevices *)lParam;
  540. hwndTV = GetDlgItem( hWnd, IDC_LV_DEVICES );
  541. break;
  542. case WM_NOTIFY:
  543. {
  544. LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
  545. HWND hwndCtl = pnmtv->hdr.hwndFrom;
  546. UINT uCode = pnmtv->hdr.code;
  547. // check for item changes in the device listview.
  548. // if an item has changed its selected state, then update the files listview
  549. //
  550. if( hwndCtl != hwndTV )
  551. {
  552. break;
  553. }
  554. switch( uCode )
  555. {
  556. case TVN_SELCHANGED:
  557. if( pnmtv->itemNew.state & LVIS_SELECTED )
  558. {
  559. HTREEITEM hItem = (HTREEITEM) pnmtv->itemNew.hItem;
  560. CItemData *pItemDevice = (CItemData *) TreeView_GetLParam( hwndTV, hItem );
  561. // Check for NULL. Without this, we crash when refreshing the display.
  562. // All pDevice values have been cleared, and we get this message as the
  563. // devices are being removed from the tree view as the selection moves
  564. // from the device being removed, to the next in the list
  565. if( NULL != pItemDevice )
  566. {
  567. // Serialize the device changes, so that we finish changing devices
  568. // before another change begins
  569. if( !fSelChangeInProgress )
  570. {
  571. fSelChangeInProgress = TRUE;
  572. PostMessage( hWnd, WM_DRM_UPDATEDEVICE, (WPARAM)hItem, 0 );
  573. fSelChangeInProgress = FALSE;
  574. }
  575. }
  576. }
  577. break;
  578. case TVN_GETDISPINFO:
  579. {
  580. LPNMTVDISPINFO lptvdi = (LPNMTVDISPINFO) lParam;
  581. INT nImage;
  582. CItemData *pItemData = (CItemData *) TreeView_GetLParam( hwndTV, lptvdi->item.hItem );
  583. if( NULL != pItemData )
  584. {
  585. if( pItemData->m_fIsDevice )
  586. {
  587. nImage = 0;
  588. }
  589. else
  590. {
  591. nImage = ( (lptvdi->item.state & TVIS_EXPANDED) ? 2 : 1 );
  592. }
  593. if( TVIF_IMAGE & lptvdi->item.mask )
  594. {
  595. lptvdi->item.iImage = nImage;
  596. }
  597. if( TVIF_SELECTEDIMAGE & lptvdi->item.mask )
  598. {
  599. lptvdi->item.iSelectedImage = nImage;
  600. }
  601. }
  602. }
  603. break;
  604. case TVN_ITEMEXPANDING:
  605. if( TVE_EXPAND & pnmtv->action )
  606. {
  607. // If the item has not been expanded once already,
  608. // add all its children
  609. //
  610. if( !(pnmtv->itemNew.state & TVIS_EXPANDEDONCE) )
  611. {
  612. BOOL fDeviceItem;
  613. fDeviceItem = ( NULL == TreeView_GetParent(hwndTV, pnmtv->itemNew.hItem) );
  614. cDevices->AddChildren( pnmtv->itemNew.hItem, fDeviceItem );
  615. }
  616. }
  617. else if( TVE_COLLAPSE & pnmtv->action )
  618. {
  619. // Do nothing
  620. }
  621. break;
  622. default:
  623. break;
  624. }
  625. }
  626. break;
  627. // Display the context menu for this device
  628. case WM_CONTEXTMENU :
  629. {
  630. HMENU hMenuLoad;
  631. HMENU hMenu;
  632. hMenuLoad = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT_MENU));
  633. hMenu = GetSubMenu(hMenuLoad, 0);
  634. TrackPopupMenu( hMenu,
  635. TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  636. LOWORD(lParam),
  637. HIWORD(lParam),
  638. 0,
  639. hWnd,
  640. NULL);
  641. DestroyMenu(hMenuLoad);
  642. break;
  643. }
  644. case WM_COMMAND :
  645. {
  646. // Show properties dialog for device
  647. if( wParam == IDM_PROPERTIES )
  648. {
  649. HTREEITEM hTree;
  650. CItemData* pItemData;
  651. // Get selected item
  652. hTree = TreeView_GetSelection( cDevices->GetHwnd_TV() );
  653. if( hTree )
  654. {
  655. // Get item data of selected item
  656. pItemData = (CItemData *) TreeView_GetLParam( hwndTV, hTree );
  657. if( pItemData )
  658. {
  659. if( pItemData->m_fIsDevice )
  660. {
  661. // Show the device property dialog
  662. DialogBoxParam( g_hInst,
  663. MAKEINTRESOURCE(IDD_PROPERTIES_DEVICE),
  664. g_hwndMain,
  665. DeviceProp_DlgProc,
  666. (LPARAM)pItemData );
  667. }
  668. else
  669. {
  670. // Show the device property dialog
  671. DialogBoxParam( g_hInst,
  672. MAKEINTRESOURCE(IDD_PROPERTIES_STORAGE),
  673. g_hwndMain,
  674. StorageProp_DlgProc,
  675. (LPARAM)pItemData );
  676. }
  677. }
  678. }
  679. }
  680. break;
  681. }
  682. case WM_DRM_UPDATEDEVICE:
  683. cDevices->UpdateSelection( (HTREEITEM)wParam, TRUE );
  684. break;
  685. default:
  686. break;
  687. }
  688. return 0;
  689. }