// // Microsoft Windows Media Technologies // Copyright (C) Microsoft Corporation, 1999 - 2001. All rights reserved. // // // This workspace contains two projects - // 1. ProgHelp which implements the Progress Interface // 2. The Sample application WmdmApp. // // ProgHelp.dll needs to be registered first for the SampleApp to run. // Includes // #include "appPCH.h" // Local variables // // Constants // #define MIN_DEVICEWND_W 200 // Macros // // Local functions // INT_PTR CALLBACK Device_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); ///////////////////////////////////////////////////////////////////// // // Function implementations // CDevices::CDevices() { m_hwndDevices = NULL; m_hwndDevices_TV = NULL; m_himlSmall = NULL; } CDevices::~CDevices() { } HWND CDevices::GetHwnd( void ) { return m_hwndDevices; } HWND CDevices::GetHwnd_TV( void ) { return m_hwndDevices_TV; } BOOL CDevices::Create( HWND hwndParent ) { BOOL fRet = FALSE; // Create the Devices dialog // m_hwndDevices = CreateDialogParam( g_hInst, MAKEINTRESOURCE( IDD_DEVICES ), hwndParent, Device_DlgProc, (LPARAM)this ); ExitOnNull( m_hwndDevices ); m_hwndDevices_TV = GetDlgItem( m_hwndDevices, IDC_LV_DEVICES ); // Initialize image list // ExitOnFalse( InitImageList() ); // Show the window // ShowWindow( m_hwndDevices, SW_SHOW ); fRet = TRUE; lExit: return fRet; } VOID CDevices::Destroy( void ) { RemoveAllItems(); if( m_hwndDevices ) { DestroyWindow( m_hwndDevices ); } if( m_himlSmall ) { ImageList_Destroy( m_himlSmall ); } } VOID CDevices::OnSize( LPRECT prcMain ) { INT nW, nH; nW = max( (prcMain->right - prcMain->left)/4, MIN_DEVICEWND_W ); nH = prcMain->bottom - prcMain->top; SetWindowPos( m_hwndDevices, NULL, -4, 0, nW, nH, SWP_NOZORDER ); SetWindowPos( m_hwndDevices_TV, NULL, 0, 0, nW-10, nH-27, SWP_NOZORDER ); } BOOL CDevices::InitImageList( void ) { BOOL fRet = FALSE; HICON hIcon; // Init Small image list // m_himlSmall = ImageList_Create( GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, -1, 0 ); ExitOnNull( m_himlSmall ); // Load icons and add them to the image list // hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE(IDI_DEVICE) ); if( hIcon != NULL ) { ImageList_AddIcon( m_himlSmall, hIcon ); } // Add the shell folder icons to the image lsit // { CHAR szWinPath[MAX_PATH+1]; SHFILEINFO si; UINT nRet; nRet = GetWindowsDirectory( szWinPath, sizeof(szWinPath)/sizeof(szWinPath[0]) ); if (nRet > 0 && nRet <= sizeof(szWinPath)/sizeof(szWinPath[0])) { SHGetFileInfo( szWinPath, 0, &si, sizeof(si), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_ICON ); hIcon = si.hIcon; ImageList_AddIcon( m_himlSmall, hIcon ); SHGetFileInfo( szWinPath, 0, &si, sizeof(si), SHGFI_SMALLICON | SHGFI_ICON | SHGFI_OPENICON ); hIcon = si.hIcon; ImageList_AddIcon( m_himlSmall, hIcon ); } else { // @@@@ Do we bail out or is ok to go on? // goto lExit; } } // Set the image list for the tree view // TreeView_SetImageList( m_hwndDevices_TV, m_himlSmall, TVSIL_NORMAL ); // Everything went Ok // fRet = TRUE; lExit: return fRet; } VOID CDevices::RemoveAllItems( void ) { HTREEITEM hItem; // Get Root item // hItem = TreeView_GetRoot( m_hwndDevices_TV ); if( hItem ) { do { // Remove all children of this device // INT nChildren = RemoveChildren( hItem ); // Get the device class associated with this item // CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hItem ); // Release device class // if( pItemData ) { delete pItemData; TreeView_SetLParam( m_hwndDevices_TV, hItem, (LPARAM)NULL ); } hItem = TreeView_GetNextSibling( m_hwndDevices_TV, hItem ); } while( hItem != NULL ); } // Then delete all the items from the list // TreeView_DeleteAllItems( m_hwndDevices_TV ); } INT CDevices::RemoveChildren( HTREEITEM hItem ) { BOOL nChildren = 0; HTREEITEM hNextItem; hNextItem = TreeView_GetChild( m_hwndDevices_TV, hItem ); if( hNextItem ) { do { nChildren++; // Remove all children of this device // nChildren += RemoveChildren( hNextItem ); // Get the storage class associated with this item // CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hNextItem ); // Release storage class // if( pItemData ) { delete pItemData; TreeView_SetLParam( m_hwndDevices_TV, hNextItem, (LPARAM)NULL ); } hNextItem = TreeView_GetNextSibling( m_hwndDevices_TV, hNextItem ); } while( hNextItem != NULL ); } return nChildren; } BOOL CDevices::AddItem( CItemData *pItemData ) { BOOL fRet = TRUE; HTREEITEM hItem; TVINSERTSTRUCT tvis; // Set up the item information // tvis.hParent = TVI_ROOT; tvis.hInsertAfter = TVI_SORT; tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_CHILDREN; tvis.item.pszText = pItemData->m_szName; tvis.item.iImage = I_IMAGECALLBACK; tvis.item.iSelectedImage = I_IMAGECALLBACK; tvis.item.lParam = (LPARAM)pItemData; tvis.item.cChildren = 0; // Add the item // hItem = TreeView_InsertItem( m_hwndDevices_TV, &tvis ); if( NULL == hItem ) { return FALSE; } // If there are children, update the item // if( HasSubFolders(hItem) ) { tvis.item.mask = TVIF_HANDLE | TVIF_CHILDREN; tvis.item.hItem = hItem; tvis.item.cChildren = 1; TreeView_SetItem( m_hwndDevices_TV, &(tvis.item) ); } return fRet; } INT CDevices::AddChildren( HTREEITEM hItem, BOOL fDeviceItem ) { INT nChildren = 0; HRESULT hr; IWMDMEnumStorage *pEnumStorage; // Get the storage enumerator associated with the hItem and // CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hItem ); ExitOnNull( pItemData ); pEnumStorage = pItemData->m_pEnumStorage; ExitOnNull( pEnumStorage ); // Reset the storage enumerator // hr = pEnumStorage->Reset(); ExitOnFail( hr ); // Add the appropriate list of files to the ListView // while( TRUE ) { IWMDMStorage *pWmdmStorage; CItemData *pItemStorage; ULONG ulFetched; hr = pEnumStorage->Next( 1, &pWmdmStorage, &ulFetched ); if( hr != S_OK ) { break; } if( ulFetched != 1 ) { ExitOnFail( hr = E_UNEXPECTED ); } pItemStorage = new CItemData; if( pItemStorage ) { hr = pItemStorage->Init( pWmdmStorage ); if( SUCCEEDED(hr) && pItemStorage->m_dwAttributes & WMDM_FILE_ATTR_FOLDER ) { HTREEITEM hNewItem; TVINSERTSTRUCT tvis; // Set up the item information // tvis.hParent = hItem; tvis.hInsertAfter = TVI_SORT; tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_CHILDREN; tvis.item.pszText = pItemStorage->m_szName; tvis.item.iImage = I_IMAGECALLBACK; tvis.item.iSelectedImage = I_IMAGECALLBACK; tvis.item.lParam = (LPARAM)pItemStorage; tvis.item.cChildren = 0; // Add the item // hNewItem = TreeView_InsertItem( m_hwndDevices_TV, &tvis ); if( hNewItem ) { nChildren++; // If there are children, update the item // if( HasSubFolders(hNewItem) ) { tvis.item.mask = TVIF_HANDLE | TVIF_CHILDREN; tvis.item.hItem = hNewItem; tvis.item.cChildren = 1; TreeView_SetItem( m_hwndDevices_TV, &(tvis.item) ); } } else { delete pItemStorage; } } else { delete pItemStorage; } } pWmdmStorage->Release(); } lExit: return nChildren; } BOOL CDevices::HasSubFolders( HTREEITEM hItem ) { BOOL fRet = FALSE; // Get the storage enumeration interface from the item // CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hItem ); ExitOnNull( pItemData ); // If the item is a device or has the has-subfolders attribute set, // then return TRUE. Otherwise, return FALSE // if( pItemData->m_fIsDevice ) { fRet = TRUE; } else if( pItemData->m_dwAttributes & WMDM_STORAGE_ATTR_HAS_FOLDERS ) { fRet = TRUE; } else { fRet = FALSE; } lExit: return fRet; } HTREEITEM CDevices::GetSelectedItem( LPARAM *pLParam ) { HTREEITEM hItem = TreeView_GetSelection( m_hwndDevices_TV ); if( hItem ) { // Return the lParam value of the item that is selected // if( pLParam ) { *pLParam = TreeView_GetLParam( m_hwndDevices_TV, hItem ); } } return hItem; } BOOL CDevices::SetSelectedItem( HTREEITEM hItem ) { return TreeView_SelectItem( m_hwndDevices_TV, hItem ); } BOOL CDevices::UpdateSelection( HTREEITEM hItem, BOOL fDirty ) { BOOL fRet = FALSE; HRESULT hr; IWMDMEnumStorage *pEnumStorage = NULL; // If hItem is NULL, then use the currently-selected item. // If no item is selected, use the first device. // if( NULL == hItem ) { hItem = GetSelectedItem( NULL ); if( NULL == hItem ) { hItem = TreeView_GetRoot( m_hwndDevices_TV ); // If there are no devices, just exit // ExitOnNull( hItem ); } } if( fDirty ) { // Remove all current files // g_cDevFiles.RemoveAllItems(); // Get the storage enumeration interface from the item // CItemData *pItemData = (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hItem ); ExitOnNull( pItemData ); pEnumStorage = pItemData->m_pEnumStorage; ExitOnNull( pEnumStorage ); // Reset the storage enumerator // hr = pEnumStorage->Reset(); ExitOnFail( hr ); // Add the appropriate list of files to the ListView // while( TRUE ) { IWMDMStorage *pWmdmStorage; CItemData *pItemStorage; ULONG ulFetched; hr = pEnumStorage->Next( 1, &pWmdmStorage, &ulFetched ); if( hr != S_OK ) { break; } if( ulFetched != 1 ) { ExitOnFail( hr = E_UNEXPECTED ); } pItemStorage = new CItemData; if( pItemStorage ) { hr = pItemStorage->Init( pWmdmStorage ); if( SUCCEEDED(hr) ) { g_cDevFiles.AddItem( pItemStorage ); } else { delete pItemStorage; } UiYield(); } pWmdmStorage->Release(); } SetSelectedItem( hItem ); } // Update the device portion of the status bar // UpdateStatusBar(); // Update the file portion of the status bar // g_cDevFiles.UpdateStatusBar(); fRet = TRUE; lExit: return fRet; } INT CDevices::GetDeviceCount( VOID ) { INT nCount = 0; HTREEITEM hItem; // Count Root items // for( hItem = TreeView_GetRoot( m_hwndDevices_TV ); hItem != NULL; hItem = TreeView_GetNextSibling( m_hwndDevices_TV, hItem ) ) { nCount++; } return nCount; } CItemData *CDevices::GetRootDevice( HTREEITEM hItem ) { HTREEITEM hRootItem; while( TRUE ) { hRootItem = hItem; hItem = TreeView_GetParent( m_hwndDevices_TV, hRootItem ); if( hItem == NULL ) { break; } } return (CItemData *) TreeView_GetLParam( m_hwndDevices_TV, hRootItem ); } VOID CDevices::UpdateStatusBar( VOID ) { INT nCount; HRESULT hr; UINT uStrID; HTREEITEM hItem; CItemData *pItemDevice; DWORD dwMemUsed; char szSpaceKB[MAX_PATH]; // Set the statusbar pane that shows the number of devices // nCount = GetDeviceCount(); if( nCount == 0 ) { uStrID = IDS_SB_DEVICE_MANY; } else if( nCount == 1 ) { uStrID = IDS_SB_DEVICE_ONE; } else { uStrID = IDS_SB_DEVICE_MANY; } g_cStatus.SetTextFormatted( SB_PANE_DEVICE, uStrID, nCount, NULL ); // If there is a selected device in the list, set the status for // the space free and used // hItem = GetSelectedItem( NULL ); if( NULL == hItem ) { // Empty the space used and free // g_cStatus.SetTextSz( SB_PANE_DEVFILES_USED, "" ); g_cStatus.SetTextSz( SB_PANE_DEVFILES_FREE, "" ); } else { pItemDevice = GetRootDevice( hItem ); ExitOnNull( pItemDevice ); hr = pItemDevice->Refresh(); ExitOnFail( hr ); dwMemUsed = pItemDevice->m_dwMemSizeKB - pItemDevice->m_dwMemFreeKB - pItemDevice->m_dwMemBadKB; // Set the space used // g_cStatus.SetTextFormatted( SB_PANE_DEVFILES_USED, IDS_SB_DEVICEFILES_USED, -1, FormatBytesToSz(dwMemUsed, 0, 1024, szSpaceKB, sizeof(szSpaceKB)) ); // Set the space free // g_cStatus.SetTextFormatted( SB_PANE_DEVFILES_FREE, IDS_SB_DEVICEFILES_FREE, -1, FormatBytesToSz(pItemDevice->m_dwMemFreeKB, 0, 1024, szSpaceKB, sizeof(szSpaceKB)) ); } lExit: return; } ///////////////////////////////////////////////////////////////////// // // Local function implementations // INT_PTR CALLBACK Device_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { WORD wId = LOWORD((DWORD)wParam); WORD wNotifyCode = HIWORD((DWORD)wParam); static CDevices *cDevices = NULL; static HWND hwndTV = NULL; static BOOL fSelChangeInProgress = FALSE; switch( uMsg ) { case WM_INITDIALOG: cDevices = (CDevices *)lParam; hwndTV = GetDlgItem( hWnd, IDC_LV_DEVICES ); break; case WM_NOTIFY: { LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam; HWND hwndCtl = pnmtv->hdr.hwndFrom; UINT uCode = pnmtv->hdr.code; // check for item changes in the device listview. // if an item has changed its selected state, then update the files listview // if( hwndCtl != hwndTV ) { break; } switch( uCode ) { case TVN_SELCHANGED: if( pnmtv->itemNew.state & LVIS_SELECTED ) { HTREEITEM hItem = (HTREEITEM) pnmtv->itemNew.hItem; CItemData *pItemDevice = (CItemData *) TreeView_GetLParam( hwndTV, hItem ); // Check for NULL. Without this, we crash when refreshing the display. // All pDevice values have been cleared, and we get this message as the // devices are being removed from the tree view as the selection moves // from the device being removed, to the next in the list if( NULL != pItemDevice ) { // Serialize the device changes, so that we finish changing devices // before another change begins if( !fSelChangeInProgress ) { fSelChangeInProgress = TRUE; PostMessage( hWnd, WM_DRM_UPDATEDEVICE, (WPARAM)hItem, 0 ); fSelChangeInProgress = FALSE; } } } break; case TVN_GETDISPINFO: { LPNMTVDISPINFO lptvdi = (LPNMTVDISPINFO) lParam; INT nImage; CItemData *pItemData = (CItemData *) TreeView_GetLParam( hwndTV, lptvdi->item.hItem ); if( NULL != pItemData ) { if( pItemData->m_fIsDevice ) { nImage = 0; } else { nImage = ( (lptvdi->item.state & TVIS_EXPANDED) ? 2 : 1 ); } if( TVIF_IMAGE & lptvdi->item.mask ) { lptvdi->item.iImage = nImage; } if( TVIF_SELECTEDIMAGE & lptvdi->item.mask ) { lptvdi->item.iSelectedImage = nImage; } } } break; case TVN_ITEMEXPANDING: if( TVE_EXPAND & pnmtv->action ) { // If the item has not been expanded once already, // add all its children // if( !(pnmtv->itemNew.state & TVIS_EXPANDEDONCE) ) { BOOL fDeviceItem; fDeviceItem = ( NULL == TreeView_GetParent(hwndTV, pnmtv->itemNew.hItem) ); cDevices->AddChildren( pnmtv->itemNew.hItem, fDeviceItem ); } } else if( TVE_COLLAPSE & pnmtv->action ) { // Do nothing } break; default: break; } } break; // Display the context menu for this device case WM_CONTEXTMENU : { HMENU hMenuLoad; HMENU hMenu; hMenuLoad = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_CONTEXT_MENU)); hMenu = GetSubMenu(hMenuLoad, 0); TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, LOWORD(lParam), HIWORD(lParam), 0, hWnd, NULL); DestroyMenu(hMenuLoad); break; } case WM_COMMAND : { // Show properties dialog for device if( wParam == IDM_PROPERTIES ) { HTREEITEM hTree; CItemData* pItemData; // Get selected item hTree = TreeView_GetSelection( cDevices->GetHwnd_TV() ); if( hTree ) { // Get item data of selected item pItemData = (CItemData *) TreeView_GetLParam( hwndTV, hTree ); if( pItemData ) { if( pItemData->m_fIsDevice ) { // Show the device property dialog DialogBoxParam( g_hInst, MAKEINTRESOURCE(IDD_PROPERTIES_DEVICE), g_hwndMain, DeviceProp_DlgProc, (LPARAM)pItemData ); } else { // Show the device property dialog DialogBoxParam( g_hInst, MAKEINTRESOURCE(IDD_PROPERTIES_STORAGE), g_hwndMain, StorageProp_DlgProc, (LPARAM)pItemData ); } } } } break; } case WM_DRM_UPDATEDEVICE: cDevices->UpdateSelection( (HTREEITEM)wParam, TRUE ); break; default: break; } return 0; }