windows-nt/Source/XPSP1/NT/shell/ext/zaxxon/zaxxon.cpp
2020-09-26 16:20:57 +08:00

1051 lines
28 KiB
C++

#include "priv.h"
#include "zaxxon.h"
#include "guids.h"
#include "shlwapip.h"
#include "mmreg.h"
#include "mmstream.h" // Multimedia stream interfaces
#include "amstream.h" // DirectShow multimedia stream interfaces
#include "ddstream.h" // DirectDraw multimedia stream interfaces
#include "resource.h"
#include "varutil.h"
#include "runtask.h"
#define COLOR3d (COLORREF)GetSysColor(COLOR_3DFACE)
#define COLORMASK (COLORREF)RGB( 255, 0, 255 )
#define PREV 0
#define PLAY 1
#define PAUSE 2
#define STOP 3
#define NEXT 4
#define MENU 5
void PlayMP3(LPTSTR pszFilename);
const TCHAR* g_crgstrStrings = TEXT("Play\0Pause\0Stop\0Previous\0Next\0Menu\0\0");
const TBBUTTON g_crgButtons[] =
{
{PLAY, PLAY, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
{PREV, PREV, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
{NEXT, NEXT, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
{MENU, MENU, TBSTATE_ENABLED, BTNS_BUTTON, 0, 0},
};
#define WMP_CONTROLS_COUNT 6
int GetButtonsWidth(HWND hwndTB)
{
LONG lButton = SendMessage(hwndTB, TB_GETBUTTONSIZE, 0, 0L);
return HIWORD(lButton) * SendMessage(hwndTB, TB_BUTTONCOUNT, 0, 0) + 1;
}
void CenterOnTopOf(BOOL fToolbar, HWND hwnd, HWND hwndOn)
{
RECT rcParent;
RECT rcSelf;
HMONITOR hmon;
GetWindowRect(hwnd, &rcSelf);
GetWindowRect(hwndOn, &rcParent);
if (fToolbar)
rcParent.right = rcParent.left + GetButtonsWidth(hwndOn);
int x = rcParent.left + (RECTWIDTH(rcParent) - RECTWIDTH(rcSelf))/2;
int y = rcParent.top - RECTHEIGHT(rcSelf);
hmon = MonitorFromWindow(hwndOn, MONITOR_DEFAULTTONEAREST);
if (hmon)
{
MONITORINFO mi;
mi.cbSize = sizeof(mi);
if (GetMonitorInfo(hmon, &mi))
{
if (x < mi.rcMonitor.left)
x = mi.rcMonitor.left;
if (y < mi.rcMonitor.top)
{
// Go below
y = rcParent.bottom;
}
if (y + RECTHEIGHT(rcSelf) > mi.rcMonitor.bottom)
y = mi.rcMonitor.bottom - RECTHEIGHT(rcSelf);
if (x + RECTWIDTH(rcSelf) > mi.rcMonitor.right)
x = mi.rcMonitor.right - RECTWIDTH(rcSelf);
}
}
SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOSIZE);
}
void FillRectClr(HDC hdc, PRECT prc, COLORREF clr)
{
COLORREF clrSave = SetBkColor(hdc, clr);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prc, NULL, 0, NULL);
SetBkColor(hdc, clrSave);
}
class CMusicExtractionTask : public CRunnableTask
{
public:
CMusicExtractionTask(CZaxxon* pzaxxon, HWND hwnd, PWSTR pszFile);
STDMETHODIMP RunInitRT(void);
private:
virtual ~CMusicExtractionTask();
TCHAR szFile[MAX_PATH];
HWND _hwnd;
CZaxxon* _pzaxxon;
};
CMusicExtractionTask::CMusicExtractionTask(CZaxxon* pzaxxon, HWND hwnd, PWSTR pszFile)
: CRunnableTask(RTF_DEFAULT), _hwnd(hwnd), _pzaxxon(pzaxxon)
{
StrCpyN(szFile, pszFile, ARRAYSIZE(szFile));
}
CMusicExtractionTask::~CMusicExtractionTask()
{
}
STDMETHODIMP CMusicExtractionTask::RunInitRT()
{
BOOL fResetImage = TRUE;
HRESULT hr = E_OUTOFMEMORY;
PWSTR psz = StrDup(szFile);
if (psz)
{
LPITEMIDLIST pidl = ILCreateFromPath(szFile);
if (pidl)
{
LPCITEMIDLIST pidlChild;
IShellFolder2* psf;
hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder2, &psf), &pidlChild);
if (SUCCEEDED(hr))
{
VARIANT v;
hr = psf->GetDetailsEx(pidlChild, &SCID_MUSIC_Artist, &v);
if (SUCCEEDED(hr))
{
TCHAR szValue[MAX_PATH];
VariantToStr(&v, szValue, ARRAYSIZE(szValue));
SendMessage(_hwnd, WM_SETARTIST, 0, (LPARAM)szValue);
}
hr = psf->GetDetailsEx(pidlChild, &SCID_MUSIC_Album, &v);
if (SUCCEEDED(hr))
{
TCHAR szValue[MAX_PATH];
VariantToStr(&v, szValue, ARRAYSIZE(szValue));
SendMessage(_hwnd, WM_SETALBUM, 0, (LPARAM)szValue);
}
hr = psf->GetDetailsEx(pidlChild, &SCID_Title, &v);
if (SUCCEEDED(hr))
{
TCHAR szValue[MAX_PATH];
VariantToStr(&v, szValue, ARRAYSIZE(szValue));
SendMessage(_hwnd, WM_SETSONG, 0, (LPARAM)szValue);
}
InvalidateRect(_hwnd, NULL, TRUE);
psf->Release();
}
ILFree(pidl);
}
if (PathRemoveFileSpec(psz))
{
PathAppend(psz, TEXT("folder.gif"));
if (!PathFileExists(psz))
{
PathRemoveFileSpec(psz);
PathAppend(psz, TEXT("folder.jpg"));
}
if (PathFileExists(psz))
{
if (_pzaxxon->_pThumbnail)
{
_pzaxxon->_pThumbnail->Release();
_pzaxxon->_pThumbnail = NULL;
}
hr = CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_IThumbnail, (void **)&(_pzaxxon->_pThumbnail));
if (SUCCEEDED(hr))
{
RECT rc;
GetWindowRect(_hwnd, &rc);
SIZE sz;
sz.cy = (3 * RECTHEIGHT(rc)) / 4;
sz.cx = sz.cy;
_pzaxxon->_pThumbnail->Init(_hwnd, WM_SONGTHUMBDONE);
_pzaxxon->_pThumbnail->GetBitmap(psz, 0, sz.cx, sz.cy);
fResetImage = FALSE;
}
}
}
LocalFree(psz);
}
if (fResetImage)
SendMessage(_hwnd, WM_SONGTHUMBDONE, 0, 0);;
if (_pzaxxon->_bOpacity < 200)
{
_pzaxxon->_fHide = FALSE;
SetTimer(_hwnd, 1, 30, NULL);
}
return hr;
}
void RenderTile(HWND hwnd, HDC hdc, CZaxxon* pzax)
{
BITMAP bm = {0};
RECT rc;
GetClientRect(hwnd, &rc);
MARGINS m = {0};
MARGINS s = {0};
RECT rcFrame = {0};
RECT rcText;
int y = 10;
if (pzax->_hbmpAlbumArt)
{
GetObject(pzax->_hbmpAlbumArt, sizeof (BITMAP), &bm);
HDC hdcBitmap = CreateCompatibleDC(hdc);
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcBitmap, pzax->_hbmpAlbumArt);
y = (RECTHEIGHT(rc) - bm.bmHeight) / 2;
if (pzax->_hTheme)
{
GetThemeMargins(pzax->_hTheme, NULL, SPP_USERPICTURE, 0, TMT_SIZINGMARGINS, NULL, &s);
y = (RECTHEIGHT(rc) - bm.bmHeight - m.cyBottomHeight - m.cyTopHeight - s.cyBottomHeight - s.cyTopHeight) / 2;
GetThemeMargins(pzax->_hTheme, NULL, SPP_USERPICTURE, 0, TMT_CONTENTMARGINS, NULL, &m);
rcFrame.left = 10;
rcFrame.top = y;
rcFrame.right = rcFrame.left + bm.bmWidth + m.cxLeftWidth + m.cxRightWidth;
rcFrame.bottom = rcFrame.top + bm.bmHeight + m.cyBottomHeight + m.cyTopHeight;
DrawThemeBackground(pzax->_hTheme, hdc, SPP_USERPICTURE, 0, &rcFrame, 0);
}
BitBlt(hdc, rcFrame.left+m.cxLeftWidth, y + m.cyTopHeight, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
SelectObject(hdcBitmap, hbmpOld);
DeleteDC(hdcBitmap);
}
SetBkMode(hdc, TRANSPARENT);
SIZE sz;
HFONT h = (HFONT)SelectObject(hdc, pzax->_hfont);
int cch = lstrlen(pzax->_szArtist);
GetTextExtentPoint32(hdc, pzax->_szArtist, cch, &sz);
rcText.left = bm.bmWidth + 20 + m.cxLeftWidth + m.cxRightWidth;
rcText.top = y + m.cyTopHeight;
rcText.right = rcText.left + sz.cx;
rcText.bottom = rcText.top + sz.cy;
DrawShadowText(hdc, pzax->_szArtist, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP, GetSysColor(COLOR_CAPTIONTEXT), RGB(0,0,0), 2, 2);
SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
cch = lstrlen(pzax->_szAlbum);
GetTextExtentPoint32(hdc, pzax->_szAlbum, cch, &sz);
rcText.top = rcText.bottom;
rcText.bottom = rcText.top + sz.cy;
rcText.right = rcText.left + sz.cx;
DrawText(hdc, pzax->_szAlbum, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP);
cch = lstrlen(pzax->_szSong);
GetTextExtentPoint32(hdc, pzax->_szSong, cch, &sz);
rcText.top = rcText.bottom;
rcText.bottom = rcText.top + sz.cy;
rcText.right = rcText.left + sz.cx;
DrawText(hdc, pzax->_szSong, cch, &rcText, DT_NOPREFIX | DT_SINGLELINE | DT_TOP);
SelectObject(hdc, h);
}
LRESULT ZaxxonWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CZaxxon* pzaxxon = (CZaxxon*)GetProp(hwnd, TEXT("Zaxxon"));
if (!pzaxxon && uMsg != WM_CREATE)
return DefWindowProc(hwnd, uMsg, wParam, lParam);
switch (uMsg)
{
case WM_CREATE:
{
pzaxxon = (CZaxxon*)((CREATESTRUCT*)lParam)->lpCreateParams;
SetProp(hwnd, TEXT("Zaxxon"), (HANDLE)pzaxxon);
pzaxxon->_hTheme = OpenThemeData(NULL, L"StartPanel");
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
pzaxxon->_hfont = CreateFontIndirect(&ncm.lfCaptionFont);
SIZE sz = {0};
if (pzaxxon->_hTheme)
GetThemePartSize(pzaxxon->_hTheme, NULL, SPP_USERPANE, 0, NULL, TS_TRUE, &sz);
int cy = 3 * GetSystemMetrics(SM_CYCAPTION);
if (sz.cy < cy)
sz.cy = cy;
if (sz.cx < 400)
sz.cx = 400;
SetWindowPos(hwnd, NULL, 0, 0, sz.cx, sz.cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
break;
case WM_DESTROY:
{
if (pzaxxon->_hTheme)
CloseThemeData(pzaxxon->_hTheme);
}
break;
case WM_ERASEBKGND:
if (pzaxxon->_hTheme)
{
RECT rc;
HDC hdc = (HDC)wParam;
GetClientRect(hwnd, &rc);
FillRectClr(hdc, &rc, RGB(255,0,255));
DrawThemeBackground(pzaxxon->_hTheme, hdc, SPP_USERPANE, 0, &rc, 0);
RenderTile(hwnd, hdc, pzaxxon);
return TRUE;
}
break;
case WM_SETALBUM:
StrCpy(pzaxxon->_szAlbum, (PTSTR)lParam);
break;
case WM_SETARTIST:
StrCpy(pzaxxon->_szArtist, (PTSTR)lParam);
break;
case WM_SETSONG:
StrCpy(pzaxxon->_szSong, (PTSTR)lParam);
break;
case WM_SONGTHUMBDONE:
{
if (pzaxxon->_hbmpAlbumArt)
DeleteObject(pzaxxon->_hbmpAlbumArt);
pzaxxon->_hbmpAlbumArt = (HBITMAP)lParam;
InvalidateRect(hwnd, NULL, TRUE);
if (pzaxxon->_pThumbnail)
{
pzaxxon->_pThumbnail->Release();
pzaxxon->_pThumbnail = NULL;
}
}
return TRUE;
case WM_TIMER:
if (wParam == 1)
{
BYTE bOld = pzaxxon->_bOpacity;
if (pzaxxon->_fHide)
{
if (pzaxxon->_bOpacity < 20)
{
pzaxxon->_bOpacity = 0;
ShowWindow(hwnd, SW_HIDE);
KillTimer(hwnd, 1);
}
else
pzaxxon->_bOpacity -= 20;
}
else
{
if (pzaxxon->_bOpacity > 200)
{
pzaxxon->_bOpacity = 200;
KillTimer(hwnd, 1);
if (pzaxxon->_fAllowFadeout)
SetTimer(hwnd, 2, 1000, NULL);
}
else
pzaxxon->_bOpacity += 10;
}
if (bOld != pzaxxon->_bOpacity)
SetLayeredWindowAttributes(hwnd, RGB(255,0,255), pzaxxon->_bOpacity, LWA_COLORKEY | LWA_ALPHA);
BOOL fToolbar = TRUE;
HWND hwndToPutOnTopOf = pzaxxon->_hwnd;
if (pzaxxon->_fEditorShown)
{
fToolbar = FALSE;
hwndToPutOnTopOf = pzaxxon->_pEdit->_hwnd;
}
CenterOnTopOf(fToolbar, hwnd, hwndToPutOnTopOf);
}
else if (wParam == 2)
{
KillTimer(hwnd, 2);
SetTimer(hwnd, 1, 30, NULL);
pzaxxon->_fHide = TRUE;
}
return TRUE;
case WM_SONGSTOP:
{
pzaxxon->SongStop();
DeleteObject(pzaxxon->_hbmpAlbumArt);
pzaxxon->_hbmpAlbumArt = NULL;
pzaxxon->_szArtist[0] = 0;
pzaxxon->_szSong[0] = 0;
pzaxxon->_szAlbum[0] = 0;
InvalidateRect(hwnd, NULL, TRUE);
}
return TRUE;
case WM_SONGCHANGE:
{
if (pzaxxon->_pScheduler)
{
CMusicExtractionTask* pme = new CMusicExtractionTask(pzaxxon, hwnd, (PWSTR)wParam);
pzaxxon->_pScheduler->AddTask(pme, CLSID_Zaxxon, 0, ITSAT_DEFAULT_PRIORITY);
pme->Release();
}
}
return TRUE;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
CZaxxon::CZaxxon()
{
CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC, IID_PPV_ARG(IShellTaskScheduler, &_pScheduler));
CoCreateInstance(CLSID_ZaxxonPlayer, NULL, CLSCTX_INPROC_SERVER, IID_IZaxxonPlayer, (void**)&_pzax);
_dwViewMode = NULL;
_himlHot = NULL;
_himlDef = NULL;
_hmenuOpenFolder = NULL;
_pThumbnail = NULL;
_bOpacity = 0;
_fHide = FALSE;
_fAllowFadeout = TRUE;
_fPlaying = FALSE;
_hbr = NULL;
_szArtist[0] = 0;
_szSong[0] = 0;
_szAlbum[0] = 0;
_hbmpAlbumArt = NULL;
}
CZaxxon::~CZaxxon()
{
if (_himlHot)
ImageList_Destroy(_himlHot);
if (_himlDef)
ImageList_Destroy(_himlDef);
if (_pzax)
_pzax->Release();
if (_pThumbnail)
_pThumbnail->Release();
if (_pScheduler)
_pScheduler->Release();
if (_hbr)
DeleteObject(_hbr);
if (_hmenuOpenFolder)
DestroyMenu(_hmenuOpenFolder);
}
HWND CZaxxon::_CreateWindow(HWND hwndParent)
{
if (_hwnd)
return _hwnd;
WNDCLASS wc = {0};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpszClassName = TEXT("ZaxxonSongTile");
wc.lpfnWndProc = ZaxxonWndProc;
wc.hInstance = HINST_THISDLL;
wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
RegisterClass(&wc);
_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL,
WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
CCS_NODIVIDER | CCS_NOPARENTALIGN |
CCS_NORESIZE | TBSTYLE_REGISTERDROP,
0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
if (_hwnd)
{
// Set the format to ANSI or UNICODE as appropriate.
ToolBar_SetUnicodeFormat(_hwnd, TRUE);
SetWindowTheme(_hwnd, L"TaskBar", NULL);
SendMessage(_hwnd, CCM_SETVERSION, COMCTL32_VERSION, 0);
SendMessage(_hwnd, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
// SendMessage(_hwnd, TB_ADDSTRING, NULL, (LPARAM)&g_crgstrStrings);
SendMessage(_hwnd, TB_ADDBUTTONS, ARRAYSIZE(g_crgButtons), (LPARAM)&g_crgButtons);
ToolBar_SetExtendedStyle(_hwnd, TBSTYLE_EX_DOUBLEBUFFER, TBSTYLE_EX_DOUBLEBUFFER);
_himlHot = ImageList_LoadImage(HINST_THISDLL,
MAKEINTRESOURCE(IDB_ZAXXONHOT), 16, 0, COLORMASK,
IMAGE_BITMAP, LR_CREATEDIBSECTION);
SendMessage(_hwnd, TB_SETHOTIMAGELIST, 0, (LPARAM)_himlHot);
_himlDef = ImageList_LoadImage(HINST_THISDLL,
MAKEINTRESOURCE(IDB_ZAXXONDEF), 16, 0, COLORMASK,
IMAGE_BITMAP, LR_CREATEDIBSECTION);
SendMessage(_hwnd, TB_SETIMAGELIST, 0, (LPARAM)_himlDef);
_hwndSongTile = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TRANSPARENT, TEXT("ZaxxonSongTile"), NULL,
WS_POPUP, 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, this);
_pEdit = new CZaxxonEditor(this);
_pEdit->Initialize();
_pzax->Register(_hwndSongTile);
}
return _hwnd;
}
void CZaxxon::SongStop()
{
_fPlaying = FALSE;
TBBUTTONINFO bi = {0};
bi.cbSize = sizeof(bi);
bi.dwMask = TBIF_IMAGE;
bi.iImage = PLAY;
ToolBar_SetButtonInfo(_hwnd, PLAY, &bi);
}
LRESULT CZaxxon::_OnCommand(WORD wNotifyCode, WORD wID, HWND hwnd)
{
if (!_pzax)
return 0;
switch (wNotifyCode)
{
case BN_CLICKED:
switch (wID)
{
case PLAY:
{
TBBUTTONINFO bi = {0};
bi.cbSize = sizeof(bi);
bi.dwMask = TBIF_IMAGE;
if (_fPlaying)
{
_pzax->Pause();
_fPlaying = FALSE;
bi.iImage = PLAY;
}
else
{
_pzax->Play();
_fPlaying = TRUE;
bi.iImage = PAUSE;
}
ToolBar_SetButtonInfo(_hwnd, PLAY, &bi);
}
break;
case PAUSE:
_pzax->Pause();
break;
case STOP:
_pzax->Stop();
_fPlaying = FALSE;
break;
case NEXT:
_pzax->NextSong();
break;
case PREV:
_pzax->PrevSong();
break;
case MENU:
{
_fEditorShown = !_fEditorShown;
BOOL fToolbar = TRUE;
HWND hwndToPutOnTopOf = _hwnd;
if (_fEditorShown)
{
fToolbar = FALSE;
hwndToPutOnTopOf = _pEdit->_hwnd;
}
_pEdit->Show(_fEditorShown);
CenterOnTopOf(fToolbar, _hwndSongTile, hwndToPutOnTopOf);
}
break;
}
}
return 1;
}
HRESULT CZaxxon::RecurseAddFile(IShellFolder* psf)
{
LPITEMIDLIST pidlItem;
IEnumIDList* penum;
if (SUCCEEDED(psf->EnumObjects(NULL, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &penum)))
{
ULONG l;
while(S_OK == penum->Next(1, &pidlItem, &l))
{
if ((SHGetAttributes(psf, pidlItem, SFGAO_FOLDER) & SFGAO_FOLDER))
{
IShellFolder* psfNext;
if (SUCCEEDED(SHBindToObjectEx(psf, pidlItem, NULL, IID_PPV_ARG(IShellFolder, &psfNext))))
{
RecurseAddFile(psfNext);
psfNext->Release();
}
}
else
{
TCHAR sz[MAX_PATH];
DisplayNameOf(psf, pidlItem, SHGDN_FORPARSING, sz, MAX_PATH);
PTSTR pszExtension = PathFindExtension(sz);
if (StrCmpI(pszExtension, TEXT(".mp3")) == 0 ||
StrCmpI(pszExtension, TEXT(".wma")) == 0)
{
_pzax->AddSong(sz);
}
}
ILFree(pidlItem);
}
}
return S_OK;
}
HRESULT CZaxxon::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr = S_FALSE;
switch (uMsg)
{
case SMC_EXEC:
{
if (psmd->uId == 1)
{
IShellMenu* psm;
if (SUCCEEDED(psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &psm))))
{
DWORD dwFlags;
IShellFolder* psf;
LPITEMIDLIST pidl;
if (SUCCEEDED(psm->GetShellFolder(&dwFlags, &pidl, IID_PPV_ARG(IShellFolder, &psf))))
{
RecurseAddFile(psf);
hr = S_OK;
psf->Release();
ILFree(pidl);
}
psm->Release();
}
}
else if (psmd->uId == 2)
{
_pzax->ClearPlaylist();
}
}
break;
case SMC_SFEXEC:
{
TCHAR sz[MAX_PATH];
DisplayNameOf(psmd->psf, psmd->pidlItem, SHGDN_FORPARSING, sz, MAX_PATH);
PTSTR pszExtension = PathFindExtension(sz);
if (StrCmpI(pszExtension, TEXT(".mp3")) == 0)
{
_pzax->AddSong(sz);
}
hr = S_OK;
}
break;
case SMC_INITMENU:
{
IShellMenu* psm;
if (SUCCEEDED(psmd->punk->QueryInterface(IID_PPV_ARG(IShellMenu, &psm))))
{
HMENU hmenu;
DWORD dwFlags = SMSET_BOTTOM;
if (psmd->uIdParent == 100)
{
hmenu = CreateMenu();
AppendMenu(hmenu, MF_SEPARATOR, -1, NULL);
AppendMenu(hmenu, MF_STRING, 2, TEXT("Clear Playlist"));
AppendMenu(hmenu, MF_STRING, 1, TEXT("Play Folder"));
}
else
{
if (_hmenuOpenFolder == NULL)
{
_hmenuOpenFolder = CreateMenu();
AppendMenu(_hmenuOpenFolder, MF_SEPARATOR, -1, NULL);
AppendMenu(_hmenuOpenFolder, MF_STRING, 1, TEXT("Play Folder"));
}
dwFlags |= SMSET_DONTOWN;
hmenu = _hmenuOpenFolder;
}
psm->SetMenu(hmenu, NULL, dwFlags);
psm->Release();
}
return S_OK;
}
break;
}
return hr;
}
void CZaxxon::_DoMenu()
{
HRESULT hr;
LPITEMIDLIST pidl = NULL;
if (FAILED(SHGetSpecialFolderLocation(_hwnd, CSIDL_MYMUSIC, &pidl)))
SHGetSpecialFolderLocation(_hwnd, CSIDL_MYDOCUMENTS, &pidl);
if (pidl)
{
IShellFolder* psf;
hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidl, &psf));
if (SUCCEEDED(hr))
{
ITrackShellMenu* ptsm;
hr = CoCreateInstance(CLSID_TrackShellMenu, NULL, CLSCTX_INPROC_SERVER, IID_ITrackShellMenu, (void**)&ptsm);
if (SUCCEEDED(hr))
{
RECT rc;
POINTL pt;
ptsm->Initialize(this, 100, ANCESTORDEFAULT, SMINIT_TOPLEVEL | SMINIT_NOSETSITE | SMINIT_VERTICAL);
ptsm->SetShellFolder(psf, pidl, NULL, SMSET_TOP | SMSET_USEBKICONEXTRACTION);
ToolBar_GetRect(_hwnd, MENU, &rc);
MapWindowPoints(_hwnd, HWND_DESKTOP, (POINT*)&rc, 2);
pt.x = rc.left;
pt.y = rc.top;
ptsm->Popup(_hwnd, &pt, (RECTL*)&rc, MPPF_TOP);
ptsm->Release();
}
psf->Release();
}
ILFree(pidl);
}
}
LRESULT CZaxxon::_OnNotify(LPNMHDR pnm)
{
LRESULT lres = 0;
switch(pnm->code)
{
case TBN_GETOBJECT:
{
NMOBJECTNOTIFY*pon = (NMOBJECTNOTIFY*)pnm;
pon->hResult = QueryInterface(*pon->piid, &pon->pObject);
lres = 1;
}
break;
case TBN_HOTITEMCHANGE:
{
NMTBHOTITEM* phi = (NMTBHOTITEM*)pnm;
if (phi->dwFlags & HICF_ENTERING)
{
_fAllowFadeout = FALSE;
_fHide = FALSE;
if (_fPlaying)
{
ShowWindow(_hwndSongTile, SW_SHOW);
SetTimer(_hwndSongTile, 1, 30, NULL);
KillTimer(_hwndSongTile, 2);
}
}
else if (phi->dwFlags & HICF_LEAVING)
{
_fAllowFadeout = TRUE;
_fHide = TRUE;
SetTimer(_hwndSongTile, 1, 30, NULL);
KillTimer(_hwndSongTile, 2);
}
}
break;
}
return lres;
}
STDMETHODIMP CZaxxon::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
static const QITAB qit[] = {
QITABENT(CZaxxon, IWinEventHandler),
QITABENT(CZaxxon, IDropTarget),
{ 0 },
};
HRESULT hres = QISearch(this, qit, riid, ppvObj);
if (FAILED(hres))
hres = CToolBand::QueryInterface(riid, ppvObj);
return hres;
}
STDMETHODIMP CZaxxon::GetWindow(HWND * phwnd)
{
*phwnd = _CreateWindow(_hwndParent);
return *phwnd? S_OK : E_FAIL;
}
STDMETHODIMP CZaxxon::GetBandInfo(DWORD dwBandID, DWORD fViewMode,
DESKBANDINFO* pdbi)
{
LONG lButton = SendMessage(_hwnd, TB_GETBUTTONSIZE, 0, 0L);
UINT ucy;
UINT ucx;
if (fViewMode & (DBIF_VIEWMODE_FLOATING |DBIF_VIEWMODE_VERTICAL))
{
ucy = HIWORD(lButton) * SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0) + 1;
ucx = LOWORD(lButton);
}
else
{
ucx = HIWORD(lButton) * SendMessage(_hwnd, TB_BUTTONCOUNT, 0, 0) + 1;
ucy = LOWORD(lButton);
}
_dwBandID = dwBandID;
_dwViewMode = fViewMode;
pdbi->ptMinSize.x = LOWORD(lButton) * 1;
pdbi->ptMinSize.y = ucy;
pdbi->ptMaxSize.y = ucy;
pdbi->ptMaxSize.x = ucx;
pdbi->ptActual.y = ucy;
pdbi->ptActual.x = ucx;
pdbi->ptIntegral.y = 1;
pdbi->ptIntegral.x = 1;
if (pdbi->dwMask & DBIM_TITLE)
{
StrCpy(pdbi->wszTitle, TEXT("Zaxxon"));
}
return S_OK;
}
STDMETHODIMP CZaxxon::ShowDW(BOOL fShow)
{
return CToolBand::ShowDW(fShow);
}
STDMETHODIMP CZaxxon::CloseDW(DWORD dw)
{
SendMessage(_hwnd, TB_SETIMAGELIST, 0, NULL);
SendMessage(_hwnd, TB_SETHOTIMAGELIST, 0, NULL);
return CToolBand::CloseDW(dw);
}
STDMETHODIMP CZaxxon::TranslateAcceleratorIO(LPMSG lpMsg)
{
return E_NOTIMPL;
}
STDMETHODIMP CZaxxon::HasFocusIO()
{
return E_NOTIMPL;
}
STDMETHODIMP CZaxxon::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
{
return S_OK;
}
STDMETHODIMP CZaxxon::IsWindowOwner(HWND hwnd)
{
return (hwnd == _hwnd)? S_OK : S_FALSE;
}
STDMETHODIMP CZaxxon::OnWinEvent(HWND hwnd, UINT dwMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
{
HRESULT hres = S_FALSE;
switch (dwMsg)
{
case WM_COMMAND:
*plres = _OnCommand(HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
hres = S_OK;
break;
case WM_NOTIFY:
*plres = _OnNotify((LPNMHDR)lParam);
hres = S_OK;
break;
case WM_ENDSESSION:
_pzax->Stop();
hres = S_OK;
break;
}
return hres;
}
STDMETHODIMP CZaxxon::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
*pdwEffect = DROPEFFECT_MOVE;
return S_OK;
}
STDMETHODIMP CZaxxon::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
return S_OK;
}
STDMETHODIMP CZaxxon::DragLeave(void)
{
return S_OK; // Yea so?
}
STDMETHODIMP CZaxxon::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
STGMEDIUM medium;
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
if (SUCCEEDED(pdtobj->GetData(&fmte, &medium)))
{
HDROP hdrop = (HDROP)medium.hGlobal;
if (hdrop)
{
int c = DragQueryFile(hdrop, -1, NULL, 0);
if (c > 0)
{
for (int i=0; i < c;i++)
{
TCHAR szPath[MAX_PATH];
DragQueryFile(hdrop, i, szPath, ARRAYSIZE(szPath));
_pzax->AddSong(szPath);
}
}
}
}
return S_OK;
}
HRESULT CZaxxon_CreateInstance(IUnknown *punk, REFIID riid, void **ppv)
{
HRESULT hr;
CZaxxon *pzax = new CZaxxon;
if (pzax)
{
hr = pzax->QueryInterface(riid, ppv);
pzax->Release();
}
else
{
hr = E_OUTOFMEMORY;
*ppv = NULL;
}
return hr;
}
STDMETHODIMP CZaxxon::GetClassID(CLSID *pClassID)
{
*pClassID = CLSID_Zaxxon;
return S_OK;
}
STDMETHODIMP CZaxxon::Load(IStream *pStm)
{
return S_OK;
}
STDMETHODIMP CZaxxon::Save(IStream *pStm, BOOL fClearDirty)
{
return S_OK;
}