// MainDlg.cpp : Implementation of CMainDlg // // Copyright (c) Microsoft Corporation. All rights reserved. // #include "stdafx.h" #include "MainDlg.h" #include "QueryDlg.h" CComModule _Module; BEGIN_OBJECT_MAP(ObjectMap) END_OBJECT_MAP() // Node string for Advanced Query node WCHAR* g_wszAdvQuery = L"Advanced Query"; // Node string for blank metadata WCHAR* g_szUnknown = L"Unknown"; // Media types WCHAR* g_pwszMediaTypes[] = { L"audio", L"photo", L"video", L"playlist", L"other" }; // Note that attribute values retrieved by using the Player object model // might be returned in a different form or format than you see in // in Windows Media Player. For example, the Rating attribute returns a // value between 0 and 99 when using the SDK, rather than a "star" rating. // (For details about how to convert the 0-99 value to "stars", see // UserRating Attribute in the Attribute Reference section of the documentation. // Params to build Audio tree NODEPARAM g_pAudioNodes[] = { { L"Artist", L"Artist" }, { L"Album", L"WM/AlbumTitle" }, { L"Songs", NULL }, { L"Genre", L"Genre" }, { L"Year", L"ReleaseDateYear" }, { L"Rating", L"UserRating" } }; // Params to build Photo tree NODEPARAM g_pPhotoNodes[] = { { L"All Pictures", NULL }, { L"Keywords", L"Comment" }, { L"Date Taken", L"DateTakenYear" }, { L"Rating", L"UserRating" }, { L"Folder", L"Folder" } }; // Params to build Video tree NODEPARAM g_pVideoNodes[] = { { L"All Video", NULL }, { L"Actors", L"Author" }, { L"Genre", L"Genre" }, { L"Rating", L"UserRating" } }; // Params to build Playlist tree NODEPARAM g_pPlaylistNodes[] = { { L"My Playlists", NULL }, }; // Params to build Other tree NODEPARAM g_pOtherNodes[] = { { L"Other Media", NULL }, { L"Folder", L"Folder" } }; // Launch the dialog when the application launchs extern "C" int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPWSTR /*lpCmdLine*/, int /*nShowCmd*/) { CoInitialize(NULL); _Module.Init(ObjectMap, hInstance, NULL); CMainDlg dlg; dlg.DoModal(); CoUninitialize(); return 0; } ///////////////////////////////////////////////////////////////////////////// // CMainDlg /*********************************************************************** * Constructor ***********************************************************************/ CMainDlg::CMainDlg() { m_pView = NULL; // Initial selection is Audio m_mtCurMediaType = AUDIO; m_cSchemaCount = sizeof(g_pAudioNodes) / sizeof(g_pAudioNodes[0]); m_pnpNodeParams = g_pAudioNodes; m_bstrMediaType = g_pwszMediaTypes[m_mtCurMediaType]; // Use prenode to keep track current clicking on the tree m_hPreNode = NULL; } /*********************************************************************** * Destructor ***********************************************************************/ CMainDlg::~CMainDlg() { } /*********************************************************************** * OnInitDialog * * Initialize member variables of handlers * Initialize WMP OCX ***********************************************************************/ LRESULT CMainDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { ::InitCommonControls(); AtlAxWinInit(); // dialog items m_hLibTree = GetDlgItem(IDC_TREE); m_hDetailList = GetDlgItem(IDC_DETAILLIST); // Create a WMP OCX CreateWmpOcx(); // Fill in combo box for media type HWND hMediaTypeList = GetDlgItem(IDC_MEDIATYPELIST); SendMessage(hMediaTypeList, CB_ADDSTRING, 0, (LPARAM)L"Music"); SendMessage(hMediaTypeList, CB_ADDSTRING, 0, (LPARAM)L"Pictures"); SendMessage(hMediaTypeList, CB_ADDSTRING, 0, (LPARAM)L"Video"); SendMessage(hMediaTypeList, CB_ADDSTRING, 0, (LPARAM)L"Playlists"); SendMessage(hMediaTypeList, CB_ADDSTRING, 0, (LPARAM)L"Other Media"); SendMessage(hMediaTypeList, CB_SETCURSEL, 0, (LPARAM)m_mtCurMediaType); // Use IWMPLibraryServices to enumerate the libries and fill in combo box HRESULT hr = E_POINTER; LONG lLibCount = 0; HWND hLibList = GetDlgItem(IDC_LIBLIST); CComPtr spLibSvc; if(m_spPlayer != NULL) { hr = m_spPlayer->QueryInterface(&spLibSvc); } if(SUCCEEDED(hr) && spLibSvc) { hr = spLibSvc->getCountByType(wmpltAll, &lLibCount); } if(SUCCEEDED(hr)) { for(LONG i = 0; i < lLibCount; i++) { CComPtr spLib; CComBSTR bstrLibName; hr = spLibSvc->getLibraryByType(wmpltAll, i , &spLib); if(SUCCEEDED(hr) && spLib) { hr = spLib->get_name(&bstrLibName); } if(SUCCEEDED(hr)) { SendMessage(hLibList, CB_ADDSTRING, 0, (LPARAM)bstrLibName.m_str); } } } SendMessage(hLibList, CB_SETCURSEL, 0, 0); // Set WordWheel text to Search... SetDlgItemText(IDC_WORDWHEEL, L"Search..."); // Set m_spMC to correct mediaCollection of currently selected library UpdateCurMC(); // Now we try to build the tree BuildLibTree(); return 0; } /*********************************************************************** * OnDestroy * Release WMP OCX ***********************************************************************/ LRESULT CMainDlg::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { // Release WMP OCX m_spMC = NULL; m_spPlayer = NULL; if(m_pView != NULL) { delete m_pView; m_pView = NULL; } return 0; } /*********************************************************************** * OnOK * User closes the dialog ***********************************************************************/ LRESULT CMainDlg::OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { EndDialog(wID); return 0; } /*********************************************************************** * OnCancel * User closes the dialog ***********************************************************************/ LRESULT CMainDlg::OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { EndDialog(wID); return 0; } /*********************************************************************** * OnChangeMediaType * Called when selection in MediaType combo box is changed ***********************************************************************/ LRESULT CMainDlg::OnChangeMediaType(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { // We use m_pnpNodeParams as a pointer to current schema parameter // This function simple change what it points and call BuildTree() m_mtCurMediaType = (MEDIATYPE)SendDlgItemMessage(IDC_MEDIATYPELIST, CB_GETCURSEL, 0, 0); switch(m_mtCurMediaType) { case AUDIO: m_cSchemaCount = sizeof(g_pAudioNodes) / sizeof(g_pAudioNodes[0]); m_pnpNodeParams = g_pAudioNodes; break; case PHOTO: m_cSchemaCount = sizeof(g_pPhotoNodes) / sizeof(g_pPhotoNodes[0]); m_pnpNodeParams = g_pPhotoNodes; break; case VIDEO: m_cSchemaCount = sizeof(g_pVideoNodes) / sizeof(g_pVideoNodes[0]); m_pnpNodeParams = g_pVideoNodes; break; case PLAYLIST: m_cSchemaCount = sizeof(g_pPlaylistNodes) / sizeof(g_pPlaylistNodes[0]); m_pnpNodeParams = g_pPlaylistNodes; break; case OTHER: m_cSchemaCount = sizeof(g_pOtherNodes) / sizeof(g_pOtherNodes[0]); m_pnpNodeParams = g_pOtherNodes; break; default: break; } m_bstrMediaType = g_pwszMediaTypes[m_mtCurMediaType]; BuildLibTree(); return 0; } /*********************************************************************** * OnChangeLib * Called when selection in Library combo box is changed ***********************************************************************/ LRESULT CMainDlg::OnChangeLib(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { // Set m_spMC to correct mediaCollection of currently selected library UpdateCurMC(); BuildLibTree(); return 0; } /*********************************************************************** * OnClickTree * Called when user clicks on the tree view ***********************************************************************/ LRESULT CMainDlg::OnClickTree(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& bHandled) { POINT p; TVHITTESTINFO hitInfo; HTREEITEM hNode = NULL; TVITEM tvi; WCHAR szVal[MAX_PATH]; HRESULT hr = S_OK; // Find out the hit point GetCursorPos(&p); ::ScreenToClient(m_hLibTree, &p); hitInfo.pt = p; hNode = TreeView_HitTest(m_hLibTree, &hitInfo); // Proceed only when user clicks on the node label if(hNode && hitInfo.flags == TVHT_ONITEMLABEL && m_spMC) { tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM; tvi.hItem = hNode; tvi.pszText = szVal; tvi.cchTextMax = MAX_PATH - 1; if(TreeView_GetItem(m_hLibTree, &tvi)) { // Reset Detail List SendMessage(m_hDetailList, LB_RESETCONTENT, 0, 0); CComPtr spQuery; // If the param is -1, it's a Advanced Query node // So we bring out the Query dialog for more conditions if(tvi.lParam < 0) { CQueryDlg dlg(m_spMC); dlg.DoModal(); hr = dlg.GetQuery(&spQuery); SetDlgItemText(IDC_DETAILTEXT, g_wszAdvQuery); } else if(m_hPreNode != hNode) // Otherwise the query condition is based on current schema node { WCHAR* szAttName = NULL; if(tvi.lParam < m_cSchemaCount) { szAttName = m_pnpNodeParams[tvi.lParam].szAttrName; } // If szAttrName is not NULL, build a query for that attribute if(szAttName) { m_spMC->createQuery(&spQuery); if(spQuery) { spQuery->addCondition( CComBSTR(szAttName), CComBSTR(L"Equals"), CComBSTR(tvi.pszText) ); } } // Show current node path if(szAttName && TreeView_GetParent(m_hLibTree, tvi.hItem)) { WCHAR szText[MAX_PATH]; StringCbPrintf(szText, sizeof(szText), L"%s > %s", szAttName, tvi.pszText); SetDlgItemText(IDC_DETAILTEXT, szText); } else { SetDlgItemText(IDC_DETAILTEXT, tvi.pszText); } } if(SUCCEEDED(hr)) { // Now we use the query to get stringCollection and show it. ShowQueryResult(spQuery); } // Remember current node m_hPreNode = hNode; } } // Let tree view do its job for UI of the tree bHandled = FALSE; return SUCCEEDED(hr)?0:1; } /*********************************************************************** Private functions ***********************************************************************/ /*********************************************************************** * CreateWmpOcx * Create a hidden WMP OCX ***********************************************************************/ HRESULT CMainDlg::CreateWmpOcx() { CComPtr spHost; RECT rect = {0, 0, 0, 0}; HRESULT hr = E_FAIL; CComPtr spHostObject; CComObject *pRemoteHost = NULL; IUnknown *punkSite = NULL; m_pView = new CAxWindow(); hr = m_pView ? S_OK : AtlHresultFromLastError(); if(SUCCEEDED(hr) && m_pView) { m_pView->Create(m_hWnd, rect, NULL, WS_CHILD | WS_VISIBLE); if(::IsWindow(m_pView->m_hWnd)) { hr = m_pView->QueryHost(IID_IObjectWithSite, (void **)&spHostObject); } if(SUCCEEDED(hr) && spHostObject.p) { hr = CComObject::CreateInstance(&pRemoteHost); if(pRemoteHost) { hr = ((IUnknown *)(IWMPRemoteMediaServices *)pRemoteHost)->QueryInterface(IID_IUnknown, (void **)&punkSite); } } if(SUCCEEDED(hr) && punkSite) { hr = spHostObject->SetSite(punkSite); punkSite->Release(); punkSite = NULL; } if(SUCCEEDED(hr)) { hr = m_pView->QueryHost(&spHost); } if(SUCCEEDED(hr) && spHost.p) { hr = spHost->CreateControl(L"{6BF52A52-394A-11d3-B153-00C04F79FAA6}", m_pView->m_hWnd, 0); } if(SUCCEEDED(hr)) { hr = m_pView->QueryControl(&m_spPlayer); } } return hr; } /*********************************************************************** * BuildLibTree * Build the tree view for current library. * Try to simulate the Windows Media Player library ***********************************************************************/ void CMainDlg::BuildLibTree() { TreeView_DeleteAllItems(m_hLibTree); HTREEITEM hParentNode = NULL; TVINSERTSTRUCT tvins; tvins.item.mask = TVIF_TEXT | TVIF_PARAM; tvins.hParent = NULL; tvins.hInsertAfter = TVI_ROOT; // Add the first node as Advanced Query so we can click on it tvins.item.lParam = (LPARAM)-1; tvins.item.pszText = g_wszAdvQuery; tvins.item.cchTextMax = lstrlen(tvins.item.pszText) + 1; hParentNode = TreeView_InsertItem(m_hLibTree, &tvins); // Now add nodes for schemas for(int iSchemaIndex = 0; iSchemaIndex < m_cSchemaCount; iSchemaIndex++) { tvins.hInsertAfter = TVI_ROOT; tvins.hParent = TVI_ROOT; tvins.item.lParam = (LPARAM)iSchemaIndex; tvins.item.pszText = m_pnpNodeParams[iSchemaIndex].szNodeName; tvins.item.cchTextMax = lstrlen(tvins.item.pszText) + 1; hParentNode = TreeView_InsertItem(m_hLibTree, &tvins); // If fEnumValues is true, we enumerate the values related to szNodeName // and add those values as subnodes if(hParentNode && m_pnpNodeParams[iSchemaIndex].szAttrName) { HRESULT hr = E_FAIL; CComBSTR bstrAttrName = m_pnpNodeParams[iSchemaIndex].szAttrName; CComPtr spSC; LONG lCount = 0; hr = m_spMC->getStringCollectionByQuery( bstrAttrName, NULL, m_bstrMediaType, bstrAttrName, VARIANT_TRUE, &spSC); if(SUCCEEDED(hr) && spSC) { hr = spSC->get_count(&lCount); } if(SUCCEEDED(hr)) { tvins.hInsertAfter = TVI_LAST; tvins.hParent = hParentNode; tvins.item.lParam = (LPARAM)iSchemaIndex; for(LONG i = 0; i < lCount; i++) { CComBSTR bstrVal; hr = spSC->item(i, &bstrVal); if(SUCCEEDED(hr)) { tvins.item.pszText = bstrVal.Length() ? bstrVal : g_szUnknown; tvins.item.cchTextMax = lstrlen(tvins.item.pszText); TreeView_InsertItem(m_hLibTree, &tvins); } } } } } } /*********************************************************************** * UpdateCurMC * Each library in IWMPLibraryServices has its own mediaCollection. * This application only shows schema tree for current library * So we need to update m_spMC for current library ***********************************************************************/ HRESULT CMainDlg::UpdateCurMC() { HRESULT hr = S_OK; LONG lLidID = -1; CComPtr spLib; CComPtr spLibSvc; lLidID = SendDlgItemMessage(IDC_LIBLIST, CB_GETCURSEL, 0, 0); if(m_spPlayer != NULL) { hr = m_spPlayer->QueryInterface(&spLibSvc); } if(spLibSvc && lLidID >= 0) { hr = spLibSvc->getLibraryByType(wmpltAll, lLidID, &spLib); } if(SUCCEEDED(hr) && spLib) { m_spMC = NULL; CComPtr spTmpMC; hr = spLib->get_mediaCollection(&spTmpMC); if(SUCCEEDED(hr) && spTmpMC) { spTmpMC->QueryInterface(&m_spMC); } } return hr; } /*********************************************************************** * ShowQueryResult * Run the query to get stringCollection and show it in the listbox ***********************************************************************/ void CMainDlg::ShowQueryResult(IWMPQuery* pQuery) { if(m_spMC) { CComPtr spSC; // Now we use the query to get stringCollection and show it. m_spMC->getStringCollectionByQuery( CComBSTR(L"Title"), pQuery, m_bstrMediaType, CComBSTR(L"Title"), VARIANT_TRUE, &spSC); if(spSC) { LONG lCount = 0; spSC->get_count(&lCount); for(LONG i = 0; i < lCount; i++) { CComBSTR bstrVal; spSC->item(i, &bstrVal); if(bstrVal.m_str) { SendMessage(m_hDetailList, LB_ADDSTRING, 0, (LPARAM)bstrVal.m_str); } } } } }