mirror of https://github.com/tongzx/nt5src
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.
2205 lines
64 KiB
2205 lines
64 KiB
//****************************************************************************
|
|
//
|
|
// Module: MMSE.DLL
|
|
// File: mmse.c
|
|
// Content: This file contains the moudle initialization.
|
|
// History:
|
|
// 06/1994 -By- Vij Rajarajan (VijR)
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1991-1994
|
|
//
|
|
//****************************************************************************
|
|
|
|
#define INITGUID
|
|
#include "mmcpl.h"
|
|
#include <coguid.h>
|
|
#include <oleguid.h>
|
|
#include <shlguid.h>
|
|
#include <mmddk.h>
|
|
#include <mmreg.h>
|
|
#include <msacm.h>
|
|
#include <msacmdrv.h>
|
|
#include <vfw.h>
|
|
|
|
#include <shlobj.h>
|
|
#undef INITGUID
|
|
#include <shlobjp.h>
|
|
//****************************************************************************
|
|
// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
|
|
//****************************************************************************
|
|
|
|
#include <commctrl.h>
|
|
#include <prsht.h>
|
|
#include "draw.h"
|
|
#include "utils.h"
|
|
#include "medhelp.h"
|
|
|
|
/*
|
|
***************************************************************
|
|
* Typedefs
|
|
***************************************************************
|
|
*/
|
|
typedef HWND (VFWAPIV * FN_MCIWNDCREATE)();
|
|
|
|
//---------------------------------------------------------------------------
|
|
// MMPSH class
|
|
//---------------------------------------------------------------------------
|
|
|
|
typedef struct _mmInfoList MMINFOLIST;
|
|
typedef MMINFOLIST * PMMINFOLIST;
|
|
|
|
typedef struct _mmInfoList
|
|
{
|
|
TCHAR szInfoDesc[80];
|
|
LPSTR pszInfo;
|
|
FOURCC ckid;
|
|
PMMINFOLIST pNext;
|
|
};
|
|
|
|
|
|
// mmse class structure. This is used for instances of
|
|
// IPersistFolder, IShellFolder, and IShellDetails.
|
|
typedef struct _mmpsh
|
|
{
|
|
// We use the pf also as our IUnknown interface
|
|
IShellExtInit sei; // 1st base class
|
|
IShellPropSheetExt pse; // 2nd base class
|
|
LPDATAOBJECT pdtobj;
|
|
UINT cRef; // reference count
|
|
LPTSTR pszFileObj;
|
|
UINT uLen;
|
|
short iMediaType;
|
|
PVOID pAudioFormatInfo;
|
|
PVOID pVideoFormatInfo;
|
|
HPALETTE hPal;
|
|
HBITMAP hDispBMP;
|
|
HICON hIcon;
|
|
PMMINFOLIST pInfoList;
|
|
} mmpsh, * PMMPSH;
|
|
|
|
/*
|
|
***************************************************************
|
|
* Defines
|
|
***************************************************************
|
|
*/
|
|
#define MIDICOPYRIGHTSTR pAudioFormatInfo
|
|
#define MIDISEQNAMESTR pVideoFormatInfo
|
|
|
|
#define MAXNUMSTREAMS 50
|
|
|
|
/*
|
|
***************************************************************
|
|
* File Globals
|
|
***************************************************************
|
|
*/
|
|
int g_cRef = 0;
|
|
|
|
SZCODE cszWavExt[] = TEXT(".WAV");
|
|
SZCODE cszMIDIExt[] = TEXT(".MID");
|
|
SZCODE cszRMIExt[] = TEXT(".RMI");
|
|
SZCODE cszAVIExt[] = TEXT(".AVI");
|
|
SZCODE cszASFExt[] = TEXT(".ASF");
|
|
SZCODE cszSlash[] = TEXT("\\");
|
|
|
|
static SZCODE aszMIDIDev[] = TEXT("sequencer");
|
|
|
|
static TCHAR szDetailsTab[64];
|
|
static TCHAR szPreviewTab[64];
|
|
|
|
/*
|
|
***************************************************************
|
|
* Prototypes
|
|
***************************************************************
|
|
*/
|
|
LPTSTR PASCAL NiceName(LPTSTR sz, BOOL fNukePath);
|
|
|
|
/*
|
|
***************************************************************
|
|
***************************************************************
|
|
*/
|
|
|
|
DWORD mmpshGetFileSize(LPTSTR szFile)
|
|
{
|
|
HANDLE hFile;
|
|
OFSTRUCT of;
|
|
DWORD dwSize = 0;
|
|
|
|
hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (INVALID_HANDLE_VALUE != hFile)
|
|
{
|
|
dwSize = GetFileSize(hFile, NULL);
|
|
CloseHandle(hFile);
|
|
}
|
|
return dwSize;
|
|
}
|
|
|
|
STATIC void ReleaseInfoList(PMMPSH pmmpsh)
|
|
{
|
|
PMMINFOLIST pCur;
|
|
|
|
pCur = pmmpsh->pInfoList;
|
|
while (pCur)
|
|
{
|
|
PMMINFOLIST pTmp;
|
|
|
|
pTmp = pCur;
|
|
pCur = pCur->pNext;
|
|
LocalFree((HLOCAL)pTmp->pszInfo);
|
|
LocalFree((HLOCAL)pTmp);
|
|
}
|
|
pmmpsh->pInfoList = NULL;
|
|
}
|
|
|
|
|
|
STATIC BOOL AddInfoToList(PMMPSH pmmpsh, LPSTR pInfo, FOURCC ckid)
|
|
{
|
|
PMMINFOLIST pCur;
|
|
int idStr;
|
|
|
|
for (pCur = pmmpsh->pInfoList; pCur && pCur->pNext ; pCur = pCur->pNext)
|
|
if (pCur->ckid == ckid)
|
|
return TRUE;
|
|
|
|
if (!pCur)
|
|
{
|
|
pCur = pmmpsh->pInfoList = (PMMINFOLIST)LocalAlloc(LPTR, sizeof(MMINFOLIST));
|
|
}
|
|
else
|
|
{
|
|
pCur->pNext = (PMMINFOLIST)LocalAlloc(LPTR, sizeof(MMINFOLIST));
|
|
pCur = pCur->pNext;
|
|
}
|
|
if (!pCur)
|
|
return FALSE;
|
|
|
|
pCur->ckid = ckid;
|
|
pCur->pszInfo = pInfo;
|
|
|
|
switch (ckid)
|
|
{
|
|
case FOURCC_INAM:
|
|
idStr = IDS_FOURCC_INAM;
|
|
break;
|
|
case FOURCC_ICOP:
|
|
idStr = IDS_FOURCC_ICOP;
|
|
break;
|
|
case FOURCC_ICMT:
|
|
idStr = IDS_FOURCC_ICMT;
|
|
break;
|
|
case FOURCC_ISBJ:
|
|
idStr = IDS_FOURCC_ISBJ;
|
|
break;
|
|
case FOURCC_ICRD:
|
|
idStr = IDS_FOURCC_ICRD;
|
|
break;
|
|
case FOURCC_IART:
|
|
idStr = IDS_FOURCC_IART;
|
|
break;
|
|
case FOURCC_DISP:
|
|
idStr = IDS_FOURCC_DISP;
|
|
break;
|
|
case FOURCC_ICMS:
|
|
idStr = IDS_FOURCC_ICMS;
|
|
break;
|
|
case FOURCC_ICRP:
|
|
idStr = IDS_FOURCC_ICRP;
|
|
break;
|
|
case FOURCC_IDIM:
|
|
idStr = IDS_FOURCC_IDIM;
|
|
break;
|
|
case FOURCC_IDPI:
|
|
idStr = IDS_FOURCC_IDPI;
|
|
break;
|
|
case FOURCC_IENG:
|
|
idStr = IDS_FOURCC_IENG;
|
|
break;
|
|
case FOURCC_IGNR:
|
|
idStr = IDS_FOURCC_IGNR;
|
|
break;
|
|
case FOURCC_IKEY:
|
|
idStr = IDS_FOURCC_IKEY;
|
|
break;
|
|
case FOURCC_ILGT:
|
|
idStr = IDS_FOURCC_ILGT;
|
|
break;
|
|
case FOURCC_IARL:
|
|
idStr = IDS_FOURCC_IARL;
|
|
break;
|
|
case FOURCC_IMED:
|
|
idStr = IDS_FOURCC_IMED;
|
|
break;
|
|
case FOURCC_IPLT:
|
|
idStr = IDS_FOURCC_IPLT;
|
|
break;
|
|
case FOURCC_IPRD:
|
|
idStr = IDS_FOURCC_IPRD;
|
|
break;
|
|
case FOURCC_ISFT:
|
|
idStr = IDS_FOURCC_ISFT;
|
|
break;
|
|
case FOURCC_ISHP:
|
|
idStr = IDS_FOURCC_ISHP;
|
|
break;
|
|
case FOURCC_ISRC:
|
|
idStr = IDS_FOURCC_ISRC;
|
|
break;
|
|
case FOURCC_ISRF:
|
|
idStr = IDS_FOURCC_ISRF;
|
|
break;
|
|
case FOURCC_ITCH:
|
|
idStr = IDS_FOURCC_ITCH;
|
|
break;
|
|
}
|
|
if (idStr)
|
|
LoadString(ghInstance, idStr, pCur->szInfoDesc, sizeof(pCur->szInfoDesc)/sizeof(TCHAR));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
typedef struct tagWaveDesc
|
|
{
|
|
DWORD dSize;
|
|
WORD wFormatSize;
|
|
NPWAVEFORMATEX pwavefmt;
|
|
} WAVEDESC,* PWAVEDESC;
|
|
|
|
|
|
STATIC BOOL PASCAL NEAR ReadWaveHeader(HMMIO hmmio,
|
|
PWAVEDESC pwd)
|
|
{
|
|
MMCKINFO mmckRIFF;
|
|
MMCKINFO mmck;
|
|
MMRESULT wError;
|
|
|
|
mmckRIFF.fccType = mmioWAVE;
|
|
if (wError = mmioDescend(hmmio, &mmckRIFF, NULL, MMIO_FINDRIFF))
|
|
{
|
|
return FALSE;
|
|
}
|
|
mmck.ckid = mmioFMT;
|
|
if (wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (mmck.cksize < sizeof(WAVEFORMAT))
|
|
{
|
|
return FALSE;
|
|
}
|
|
pwd->wFormatSize = (WORD)mmck.cksize;
|
|
pwd->pwavefmt = (NPWAVEFORMATEX)LocalAlloc(LPTR, pwd->wFormatSize);
|
|
if (!pwd->pwavefmt)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ((DWORD)mmioRead(hmmio, (HPSTR)pwd->pwavefmt, mmck.cksize) != mmck.cksize)
|
|
{
|
|
goto RetErr;
|
|
}
|
|
if (pwd->pwavefmt->wFormatTag == WAVE_FORMAT_PCM)
|
|
{
|
|
if (pwd->wFormatSize < sizeof(PCMWAVEFORMAT))
|
|
{
|
|
goto RetErr;
|
|
}
|
|
}
|
|
else if ((pwd->wFormatSize < sizeof(WAVEFORMATEX)) || (pwd->wFormatSize < sizeof(WAVEFORMATEX) + pwd->pwavefmt->cbSize))
|
|
{
|
|
goto RetErr;
|
|
}
|
|
if (wError = mmioAscend(hmmio, &mmck, 0))
|
|
{
|
|
goto RetErr;
|
|
}
|
|
mmck.ckid = mmioDATA;
|
|
if (wError = mmioDescend(hmmio, &mmck, &mmckRIFF, MMIO_FINDCHUNK))
|
|
{
|
|
goto RetErr;
|
|
}
|
|
pwd->dSize = mmck.cksize;
|
|
return TRUE;
|
|
RetErr:
|
|
LocalFree((HLOCAL)pwd->pwavefmt);
|
|
pwd->pwavefmt = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
STATIC void GetWaveInfo(HMMIO hmmio, PMMPSH pmmpsh)
|
|
{
|
|
WAVEDESC wd;
|
|
|
|
if (!ReadWaveHeader(hmmio, &wd))
|
|
return;
|
|
|
|
pmmpsh->uLen = (UINT)MulDiv(wd.dSize, 1000, wd.pwavefmt->nAvgBytesPerSec);
|
|
pmmpsh->pAudioFormatInfo = (PVOID)wd.pwavefmt;
|
|
}
|
|
|
|
STATIC void GetMCIInfo(LPTSTR pszFile, PMMPSH pmmpsh)
|
|
{
|
|
TCHAR szMIDIInfo[MAXSTR];
|
|
MCI_OPEN_PARMS mciOpen; /* Structure for MCI_OPEN command */
|
|
DWORD dwFlags;
|
|
DWORD dw;
|
|
UINT wDevID;
|
|
MCI_STATUS_PARMS mciStatus;
|
|
MCI_SET_PARMS mciSet; /* Structure for MCI_SET command */
|
|
MCI_INFO_PARMS mciInfo;
|
|
/* Open a file with an explicitly specified device */
|
|
|
|
memset(&mciOpen, 0x00, sizeof(mciOpen));
|
|
|
|
mciOpen.lpstrDeviceType = aszMIDIDev;
|
|
mciOpen.lpstrElementName = pszFile;
|
|
dwFlags = MCI_WAIT | MCI_OPEN_ELEMENT | MCI_OPEN_TYPE;
|
|
dw = mciSendCommand((MCIDEVICEID)0, MCI_OPEN, dwFlags,(DWORD_PTR)(LPVOID)&mciOpen);
|
|
if (dw)
|
|
return;
|
|
wDevID = mciOpen.wDeviceID;
|
|
|
|
mciSet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
|
|
|
|
dw = mciSendCommand(wDevID, MCI_SET, MCI_SET_TIME_FORMAT,
|
|
(DWORD_PTR) (LPVOID) &mciSet);
|
|
if (dw)
|
|
{
|
|
mciSendCommand(wDevID, MCI_CLOSE, 0L, (DWORD_PTR)0);
|
|
return;
|
|
}
|
|
|
|
mciStatus.dwItem = MCI_STATUS_LENGTH;
|
|
dw = mciSendCommand(wDevID, MCI_STATUS, MCI_STATUS_ITEM,
|
|
(DWORD_PTR) (LPTSTR) &mciStatus);
|
|
if (dw)
|
|
pmmpsh->uLen = 0;
|
|
else
|
|
pmmpsh->uLen = (UINT)mciStatus.dwReturn;
|
|
|
|
mciInfo.dwCallback = 0;
|
|
mciInfo.lpstrReturn = szMIDIInfo;
|
|
mciInfo.dwRetSize = sizeof(szMIDIInfo);
|
|
|
|
szMIDIInfo[0] = TEXT('\0');
|
|
|
|
dw = mciSendCommand(wDevID, MCI_INFO, MCI_INFO_COPYRIGHT, (DWORD_PTR)(LPVOID)&mciInfo);
|
|
|
|
if (dw == 0 && lstrlen(szMIDIInfo))
|
|
{
|
|
pmmpsh->MIDICOPYRIGHTSTR = LocalAlloc(LPTR, lstrlen(szMIDIInfo) + 1);
|
|
if (pmmpsh->MIDICOPYRIGHTSTR)
|
|
{
|
|
lstrcpy((LPTSTR)pmmpsh->MIDICOPYRIGHTSTR, szMIDIInfo);
|
|
}
|
|
}
|
|
|
|
mciInfo.lpstrReturn = szMIDIInfo;
|
|
mciInfo.dwRetSize = sizeof(szMIDIInfo);
|
|
|
|
szMIDIInfo[0] = TEXT('\0');
|
|
|
|
dw = mciSendCommand(wDevID, MCI_INFO, MCI_INFO_NAME, (DWORD_PTR)(LPVOID)&mciInfo);
|
|
|
|
if (dw == 0 && lstrlen(szMIDIInfo))
|
|
{
|
|
pmmpsh->MIDISEQNAMESTR = LocalAlloc(LPTR, lstrlen(szMIDIInfo) + 1);
|
|
if (pmmpsh->MIDISEQNAMESTR)
|
|
{
|
|
lstrcpy((LPTSTR)pmmpsh->MIDISEQNAMESTR, szMIDIInfo);
|
|
}
|
|
}
|
|
|
|
mciSendCommand(wDevID, MCI_CLOSE, 0L, (DWORD)0);
|
|
|
|
}
|
|
|
|
STATIC void GetMIDIInfo(LPTSTR pszFile, PMMPSH pmmpsh)
|
|
{
|
|
GetMCIInfo(pszFile, pmmpsh);
|
|
}
|
|
|
|
STATIC void ReadAviStreams(LPTSTR pszFile, PMMPSH pmmpsh)
|
|
{
|
|
HRESULT hr;
|
|
PAVIFILE pfile;
|
|
int i;
|
|
PAVISTREAM pavi;
|
|
PAVISTREAM apavi[MAXNUMSTREAMS]; // the current streams
|
|
AVISTREAMINFO avis;
|
|
LONG timeStart; // cached start, end, length
|
|
LONG timeEnd;
|
|
int cpavi;
|
|
TCHAR szDecSep[10];
|
|
TCHAR szListSep[10];
|
|
|
|
hr = (HRESULT)AVIFileOpen(&pfile, pszFile, 0, 0L);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DPF("Unable to open %s", pszFile);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i <= MAXNUMSTREAMS; i++)
|
|
{
|
|
if (AVIFileGetStream(pfile, &pavi, 0L, i) != AVIERR_OK)
|
|
break;
|
|
if (i == MAXNUMSTREAMS)
|
|
{
|
|
AVIStreamRelease(pavi);
|
|
DPF("Exceeded maximum number of streams");
|
|
break;
|
|
}
|
|
apavi[i] = pavi;
|
|
}
|
|
|
|
//
|
|
// Couldn't get any streams out of this file
|
|
//
|
|
if (i == 0)
|
|
{
|
|
DPF("Unable to open any streams in %s", pszFile);
|
|
if (pfile)
|
|
AVIFileRelease(pfile);
|
|
return;
|
|
}
|
|
|
|
cpavi = i;
|
|
|
|
//
|
|
// Start with bogus times
|
|
//
|
|
timeStart = 0x7FFFFFFF;
|
|
timeEnd = 0;
|
|
|
|
//bug 141733, get the local decimal and list separators
|
|
GetLocaleInfo( GetUserDefaultLCID(), LOCALE_SDECIMAL, szDecSep, sizeof(szDecSep)/sizeof(TCHAR) );
|
|
GetLocaleInfo( GetUserDefaultLCID(), LOCALE_SLIST, szListSep, sizeof(szListSep)/sizeof(TCHAR) );
|
|
|
|
//
|
|
// Walk through and init all streams loaded
|
|
//
|
|
for (i = 0; i < cpavi; i++)
|
|
{
|
|
|
|
AVIStreamInfo(apavi[i], &avis, sizeof(avis));
|
|
|
|
switch(avis.fccType)
|
|
{
|
|
case streamtypeVIDEO:
|
|
{
|
|
LONG cbFormat;
|
|
LPVOID lpFormat;
|
|
ICINFO icInfo;
|
|
HIC hic;
|
|
DWORD dwTimeLen;
|
|
DWORD dwSize;
|
|
int iFrameRate;
|
|
TCHAR szFormat[MAXSTR];
|
|
|
|
if (pmmpsh->pVideoFormatInfo)
|
|
break;
|
|
|
|
AVIStreamFormatSize(apavi[i], 0, &cbFormat);
|
|
pmmpsh->pVideoFormatInfo = (PVOID)LocalAlloc(LPTR, MAX_PATH);
|
|
if (!pmmpsh->pVideoFormatInfo)
|
|
break;
|
|
dwSize = mmpshGetFileSize(pszFile);
|
|
dwTimeLen = (DWORD)(AVIStreamEndTime(apavi[i]) - AVIStreamStartTime(apavi[i]));
|
|
iFrameRate = MulDiv(avis.dwLength, 1000000, dwTimeLen);
|
|
lpFormat = (LPVOID)LocalAlloc(LPTR, cbFormat);
|
|
if (!lpFormat)
|
|
{
|
|
goto BadFormat;
|
|
}
|
|
AVIStreamReadFormat(apavi[i], 0, lpFormat, &cbFormat);
|
|
hic = (HIC)ICLocate(FOURCC_VIDC, avis.fccHandler, lpFormat, NULL, (WORD)ICMODE_DECOMPRESS);
|
|
if (hic || ((LPBITMAPINFOHEADER)lpFormat)->biCompression == 0)
|
|
{
|
|
TCHAR szName[48];
|
|
|
|
if (((LPBITMAPINFOHEADER)lpFormat)->biCompression)
|
|
{
|
|
ICGetInfo(hic, &icInfo, sizeof(ICINFO));
|
|
ICClose(hic);
|
|
//WideCharToMultiByte(CP_ACP, 0, icInfo.szName, -1, szName, sizeof(szName), NULL, NULL);
|
|
wcscpy(szName,icInfo.szName);
|
|
}
|
|
else
|
|
{
|
|
LoadString(ghInstance, IDS_UNCOMPRESSED, szName, sizeof(szName)/sizeof(TCHAR));
|
|
}
|
|
LoadString(ghInstance, IDS_GOODFORMAT, szFormat, sizeof(szFormat)/sizeof(TCHAR));
|
|
|
|
wsprintf((LPTSTR)pmmpsh->pVideoFormatInfo, szFormat, (avis.rcFrame.right - avis.rcFrame.left),
|
|
(avis.rcFrame.bottom - avis.rcFrame.top), szListSep, ((LPBITMAPINFOHEADER)lpFormat)->biBitCount, szListSep,
|
|
avis.dwLength, szListSep, (UINT)(iFrameRate/1000), szDecSep, (UINT)(iFrameRate%1000), szListSep, MulDiv(dwSize, 1000,dwTimeLen)/1024, szListSep, szName);
|
|
|
|
goto GoodFormat;
|
|
|
|
}
|
|
BadFormat:
|
|
LoadString(ghInstance, IDS_BADFORMAT, szFormat, sizeof(szFormat)/sizeof(TCHAR));
|
|
wsprintf((LPTSTR)pmmpsh->pVideoFormatInfo, szFormat, (avis.rcFrame.right - avis.rcFrame.left),
|
|
(avis.rcFrame.bottom - avis.rcFrame.top), szListSep,
|
|
avis.dwLength, szListSep, (UINT)(iFrameRate/1000), szDecSep, (UINT)(iFrameRate%1000), szListSep, MulDiv(dwSize, 1000,dwTimeLen)/1024, szListSep);
|
|
GoodFormat:
|
|
LocalFree((HLOCAL)lpFormat);
|
|
break;
|
|
}
|
|
case streamtypeAUDIO:
|
|
{
|
|
LONG cbFormat;
|
|
|
|
AVIStreamFormatSize(apavi[i], 0, &cbFormat);
|
|
pmmpsh->pAudioFormatInfo = (LPVOID)LocalAlloc(LPTR, cbFormat);
|
|
if (!pmmpsh->pAudioFormatInfo)
|
|
break;
|
|
AVIStreamReadFormat(apavi[i], 0, pmmpsh->pAudioFormatInfo, &cbFormat);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We're finding the earliest and latest start and end points for
|
|
// our scrollbar.
|
|
//
|
|
timeStart = (LONG)min(timeStart, AVIStreamStartTime(apavi[i]));
|
|
timeEnd = (LONG)max(timeEnd, AVIStreamEndTime(apavi[i]));
|
|
}
|
|
pmmpsh->uLen = (UINT)(timeEnd - timeStart);
|
|
DPF("The file length is %d \r\n", pmmpsh->uLen);
|
|
|
|
for (i = 0; i < cpavi; i++)
|
|
{
|
|
AVIStreamRelease(apavi[i]);
|
|
}
|
|
AVIFileRelease(pfile);
|
|
}
|
|
|
|
|
|
STATIC void GetAVIInfo(LPTSTR pszFile, PMMPSH pmmpsh)
|
|
{
|
|
if (!LoadAVI())
|
|
{
|
|
DPF("****Load AVI failed**\r\n");
|
|
ASSERT(FALSE);
|
|
return;
|
|
}
|
|
if (!LoadVFW())
|
|
{
|
|
DPF("****Load VFW failed**\r\n");
|
|
ASSERT(FALSE);
|
|
FreeAVI();
|
|
return;
|
|
}
|
|
AVIFileInit();
|
|
ReadAviStreams(pszFile, pmmpsh);
|
|
AVIFileExit();
|
|
if (!FreeVFW())
|
|
{
|
|
DPF("****Free VFW failed**\r\n");
|
|
ASSERT(FALSE);
|
|
}
|
|
if (!FreeAVI())
|
|
{
|
|
DPF("****Free AVI failed**\r\n");
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
STATIC void GetASFInfo(LPTSTR pszFile, PMMPSH pmmpsh)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC void GetMediaInfo(HMMIO hmmio, PMMPSH pmmpsh)
|
|
{
|
|
switch (pmmpsh->iMediaType)
|
|
{
|
|
case MT_WAVE:
|
|
GetWaveInfo(hmmio, pmmpsh);
|
|
break;
|
|
case MT_MIDI:
|
|
GetMIDIInfo(pmmpsh->pszFileObj, pmmpsh);
|
|
break;
|
|
case MT_AVI:
|
|
GetAVIInfo(pmmpsh->pszFileObj, pmmpsh);
|
|
break;
|
|
case MT_ASF:
|
|
GetASFInfo(pmmpsh->pszFileObj, pmmpsh);
|
|
break;
|
|
}
|
|
}
|
|
|
|
STATIC HANDLE PASCAL GetRiffAll(PMMPSH pmmpsh)
|
|
{
|
|
MMCKINFO ck;
|
|
MMCKINFO ckINFO;
|
|
MMCKINFO ckRIFF;
|
|
HANDLE h = NULL;
|
|
LONG lSize;
|
|
DWORD dw;
|
|
HMMIO hmmio;
|
|
BOOL fDoneDISP;
|
|
BOOL fDoneINFO;
|
|
BOOL fDoneName;
|
|
LPSTR pInfo;
|
|
|
|
hmmio = mmioOpen(pmmpsh->pszFileObj, NULL, MMIO_ALLOCBUF | MMIO_READ);
|
|
|
|
if (!hmmio)
|
|
goto error;
|
|
|
|
GetMediaInfo(hmmio, pmmpsh);
|
|
if (pmmpsh->uLen == 0)
|
|
goto error;
|
|
mmioSeek(hmmio, 0, SEEK_SET);
|
|
|
|
/* descend the input file into the RIFF chunk */
|
|
if (mmioDescend(hmmio, &ckRIFF, NULL, 0) != 0)
|
|
goto error;
|
|
|
|
if (ckRIFF.ckid != FOURCC_RIFF)
|
|
goto error;
|
|
|
|
fDoneDISP = fDoneINFO = fDoneName = FALSE;
|
|
while (!(fDoneDISP && fDoneINFO) && !mmioDescend(hmmio, &ck, &ckRIFF, 0))
|
|
{
|
|
if (ck.ckid == FOURCC_DISP)
|
|
{
|
|
/* Read dword into dw, break if read unsuccessful */
|
|
if (mmioRead(hmmio, (LPVOID)&dw, sizeof(dw)) != (LONG)sizeof(dw))
|
|
goto error;
|
|
|
|
/* Find out how much memory to allocate */
|
|
lSize = ck.cksize - sizeof(dw);
|
|
if ((int)dw == CF_DIB && h == NULL)
|
|
{
|
|
/* get a handle to memory to hold the description and
|
|
lock it down */
|
|
|
|
if ((h = GlobalAlloc(GHND, lSize+4)) == NULL)
|
|
goto error;
|
|
|
|
if (mmioRead(hmmio, GlobalLock(h), lSize) != lSize)
|
|
goto error;
|
|
|
|
fDoneDISP = TRUE;
|
|
}
|
|
else if ((int)dw == CF_TEXT)
|
|
{
|
|
pInfo = (LPSTR)LocalAlloc(LPTR, lSize+1);//+1 not required I think
|
|
if (!pInfo)
|
|
goto error;
|
|
|
|
if (!mmioRead(hmmio, pInfo, lSize))
|
|
goto error;
|
|
|
|
AddInfoToList(pmmpsh, pInfo, ck.ckid );
|
|
fDoneName = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
else if (ck.ckid == FOURCC_LIST &&
|
|
ck.fccType == FOURCC_INFO &&
|
|
!fDoneINFO)
|
|
{
|
|
while (!mmioDescend(hmmio, &ckINFO, &ck, 0))
|
|
{
|
|
switch (ckINFO.ckid)
|
|
{
|
|
case FOURCC_ISBJ:
|
|
case FOURCC_INAM:
|
|
case FOURCC_ICOP:
|
|
case FOURCC_ICRD:
|
|
case FOURCC_IART:
|
|
case FOURCC_ICMS:
|
|
case FOURCC_ICMT:
|
|
case FOURCC_ICRP:
|
|
case FOURCC_IDIM:
|
|
case FOURCC_IARL:
|
|
case FOURCC_IDPI:
|
|
case FOURCC_IENG:
|
|
case FOURCC_IGNR:
|
|
case FOURCC_IKEY:
|
|
case FOURCC_ILGT:
|
|
case FOURCC_IMED:
|
|
case FOURCC_IPLT:
|
|
case FOURCC_IPRD:
|
|
case FOURCC_ISFT:
|
|
case FOURCC_ISHP:
|
|
case FOURCC_ISRC:
|
|
case FOURCC_ISRF:
|
|
case FOURCC_ITCH:
|
|
pInfo = (LPSTR)LocalAlloc(LPTR, ck.cksize+1);//+1 not required I think
|
|
if (!pInfo)
|
|
goto error;
|
|
|
|
if (!mmioRead(hmmio, pInfo, ck.cksize))
|
|
goto error;
|
|
|
|
AddInfoToList(pmmpsh, pInfo, ckINFO.ckid);
|
|
if (ckINFO.ckid == FOURCC_INAM)
|
|
fDoneName = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (mmioAscend(hmmio, &ckINFO, 0))
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* Ascend so that we can descend into next chunk
|
|
*/
|
|
if (mmioAscend(hmmio, &ck, 0))
|
|
break;
|
|
}
|
|
|
|
goto exit;
|
|
|
|
error:
|
|
if (h)
|
|
{
|
|
GlobalUnlock(h);
|
|
GlobalFree(h);
|
|
}
|
|
h = NULL;
|
|
ReleaseInfoList(pmmpsh);
|
|
|
|
exit:
|
|
if (hmmio)
|
|
mmioClose(hmmio,0);
|
|
return h;
|
|
}
|
|
|
|
STATIC BOOL PASCAL WaveGetFormatDescription
|
|
(
|
|
LPWAVEFORMATEX pwfx,
|
|
LPTSTR pszDesc
|
|
)
|
|
{
|
|
UINT_PTR mmr;
|
|
TCHAR pszFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
|
|
TCHAR pszFormat[ACMFORMATDETAILS_FORMAT_CHARS];
|
|
BOOL bRet = FALSE;
|
|
TCHAR szListSep[10];
|
|
//
|
|
// get the name for the format tag of the specified format
|
|
//
|
|
|
|
if (!pwfx)
|
|
{
|
|
pszDesc[0] = TEXT('\0');
|
|
return TRUE;
|
|
}
|
|
if (!LoadACM())
|
|
{
|
|
DPF("****Load ACM failed**\r\n");
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
if (NULL != pszFormatTag)
|
|
{
|
|
PACMFORMATTAGDETAILSW paftd;
|
|
|
|
//
|
|
// initialize all unused members of the ACMFORMATTAGDETAILS
|
|
// structure to zero
|
|
//
|
|
paftd = (PACMFORMATTAGDETAILSW)LocalAlloc(LPTR, sizeof(ACMFORMATTAGDETAILSW));
|
|
if (!paftd)
|
|
goto RetErr;
|
|
//
|
|
// fill in the required members of the ACMFORMATTAGDETAILS
|
|
// structure for the ACM_FORMATTAGDETAILSF_FORMATTAG query
|
|
//
|
|
paftd->cbStruct = sizeof(ACMFORMATTAGDETAILSW);
|
|
paftd->dwFormatTag = pwfx->wFormatTag;
|
|
|
|
//
|
|
// ask the ACM to find the first available driver that
|
|
// supports the specified format tag
|
|
//
|
|
mmr = acmFormatTagDetails(NULL,
|
|
paftd,
|
|
ACM_FORMATTAGDETAILSF_FORMATTAG);
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
//
|
|
// copy the format tag name into the caller's buffer
|
|
//
|
|
lstrcpy(pszFormatTag, paftd->szFormatTag);
|
|
}
|
|
else
|
|
{
|
|
static const struct _wfm_names {
|
|
UINT uFormatTag;
|
|
UINT uIDS;
|
|
} aWaveFmtNames[] = {
|
|
WAVE_FORMAT_PCM, IDS_FORMAT_PCM,
|
|
WAVE_FORMAT_ADPCM, IDS_FORMAT_ADPCM,
|
|
WAVE_FORMAT_IBM_CVSD, IDS_FORMAT_IBM_CVSD,
|
|
WAVE_FORMAT_ALAW, IDS_FORMAT_ALAW,
|
|
WAVE_FORMAT_MULAW, IDS_FORMAT_MULAW,
|
|
WAVE_FORMAT_OKI_ADPCM, IDS_FORMAT_OKI_ADPCM,
|
|
WAVE_FORMAT_IMA_ADPCM, IDS_FORMAT_IMA_ADPCM,
|
|
WAVE_FORMAT_MEDIASPACE_ADPCM, IDS_FORMAT_MEDIASPACE_ADPCM,
|
|
WAVE_FORMAT_SIERRA_ADPCM, IDS_FORMAT_SIERRA_ADPCM,
|
|
WAVE_FORMAT_G723_ADPCM, IDS_FORMAT_G723_ADPCM,
|
|
WAVE_FORMAT_DIGISTD, IDS_FORMAT_DIGISTD,
|
|
WAVE_FORMAT_DIGIFIX, IDS_FORMAT_DIGIFIX,
|
|
WAVE_FORMAT_YAMAHA_ADPCM, IDS_FORMAT_YAMAHA_ADPCM,
|
|
WAVE_FORMAT_SONARC, IDS_FORMAT_SONARC,
|
|
WAVE_FORMAT_DSPGROUP_TRUESPEECH, IDS_FORMAT_DSPGROUP_TRUESPEECH,
|
|
WAVE_FORMAT_ECHOSC1, IDS_FORMAT_ECHOSC1,
|
|
WAVE_FORMAT_AUDIOFILE_AF36, IDS_FORMAT_AUDIOFILE_AF36,
|
|
WAVE_FORMAT_APTX, IDS_FORMAT_APTX,
|
|
WAVE_FORMAT_AUDIOFILE_AF10, IDS_FORMAT_AUDIOFILE_AF10,
|
|
WAVE_FORMAT_DOLBY_AC2, IDS_FORMAT_DOLBY_AC2,
|
|
WAVE_FORMAT_GSM610, IDS_FORMAT_GSM610,
|
|
WAVE_FORMAT_G721_ADPCM, IDS_FORMAT_G721_ADPCM,
|
|
WAVE_FORMAT_CREATIVE_ADPCM, IDS_FORMAT_CREATIVE_ADPCM,
|
|
0, IDS_UNKFORMAT,
|
|
};
|
|
UINT ii;
|
|
|
|
//
|
|
// no ACM driver is available that supports the
|
|
// specified format tag. look up the tag id
|
|
// in our table of tag names (above)
|
|
//
|
|
for (ii = 0; aWaveFmtNames[ii].uFormatTag; ii++)
|
|
if (pwfx->wFormatTag == aWaveFmtNames[ii].uFormatTag)
|
|
break;
|
|
LoadString(ghInstance, aWaveFmtNames[ii].uIDS, pszFormatTag, ACMFORMATTAGDETAILS_FORMATTAG_CHARS);
|
|
}
|
|
LocalFree((HLOCAL)paftd);
|
|
}
|
|
|
|
//
|
|
// get the description of the attributes for the specified
|
|
// format
|
|
//
|
|
if (NULL != pszFormat)
|
|
{
|
|
PACMFORMATDETAILSW pafd;
|
|
|
|
//
|
|
// initialize all unused members of the ACMFORMATDETAILS
|
|
// structure to zero
|
|
//
|
|
pafd = (PACMFORMATDETAILSW)LocalAlloc(LPTR, sizeof(ACMFORMATDETAILSW));
|
|
if (!pafd)
|
|
goto RetErr;
|
|
|
|
//
|
|
// fill in the required members of the ACMFORMATDETAILS
|
|
// structure for the ACM_FORMATDETAILSF_FORMAT query
|
|
//
|
|
pafd->cbStruct = sizeof(ACMFORMATDETAILSW);
|
|
pafd->dwFormatTag = pwfx->wFormatTag;
|
|
pafd->pwfx = pwfx;
|
|
|
|
//
|
|
// the cbwfx member must be initialized to the total size
|
|
// in bytes needed for the specified format. for a PCM
|
|
// format, the cbSize member of the WAVEFORMATEX structure
|
|
// is not valid.
|
|
//
|
|
if (WAVE_FORMAT_PCM == pwfx->wFormatTag)
|
|
{
|
|
pafd->cbwfx = sizeof(PCMWAVEFORMAT);
|
|
}
|
|
else
|
|
{
|
|
pafd->cbwfx = sizeof(WAVEFORMATEX) + pwfx->cbSize;
|
|
}
|
|
|
|
//
|
|
// ask the ACM to find the first available driver that
|
|
// supports the specified format
|
|
//
|
|
mmr = acmFormatDetails(NULL, pafd, ACM_FORMATDETAILSF_FORMAT);
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
//
|
|
// copy the format attributes description into the caller's
|
|
// buffer
|
|
//
|
|
lstrcpy(pszFormat, pafd->szFormat);
|
|
}
|
|
else
|
|
{
|
|
pszFormat[0] = TEXT('\0');
|
|
}
|
|
LocalFree((HLOCAL)pafd);
|
|
}
|
|
//bug 141733, get the local decimal and list separators
|
|
GetLocaleInfo( GetUserDefaultLCID(), LOCALE_SLIST, szListSep, sizeof(szListSep)/sizeof(TCHAR) );
|
|
wsprintf(pszDesc, TEXT("%s%s %s"), pszFormatTag, szListSep, pszFormat);
|
|
bRet = TRUE;
|
|
|
|
RetErr:
|
|
if (!FreeACM())
|
|
{
|
|
DPF("****Free ACM failed**\r\n");
|
|
ASSERT(FALSE);
|
|
}
|
|
return bRet;
|
|
} // AcmAppGetFormatDescription()
|
|
|
|
|
|
|
|
STATIC void ShowInfoList(PMMPSH pmmpsh, HWND hDlg)
|
|
{
|
|
PMMINFOLIST pCur;
|
|
TCHAR* szTemp;
|
|
HWND hwndLB = GetDlgItem(hDlg, IDD_INFO_NAME);
|
|
TCHAR szNoCopyRight[MAXSTR];
|
|
int iIndex;
|
|
|
|
LoadString(ghInstance, IDS_NOCOPYRIGHT, szNoCopyRight, sizeof(szNoCopyRight)/sizeof(TCHAR));
|
|
SetDlgItemText(hDlg, IDD_COPYRIGHT, szNoCopyRight);
|
|
if (!pmmpsh->pInfoList)
|
|
{
|
|
DestroyWindow(GetDlgItem(hDlg, IDC_DETAILSINFO_GRP));
|
|
DestroyWindow(GetDlgItem(hDlg, IDC_ITEMSLABEL));
|
|
DestroyWindow(GetDlgItem(hDlg, IDC_DESCLABEL));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_INFO_NAME));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_INFO_VALUE));
|
|
return;
|
|
}
|
|
for (pCur = pmmpsh->pInfoList; pCur; pCur = pCur->pNext)
|
|
{
|
|
int nTempSize = (strlen(pCur->pszInfo)*sizeof(TCHAR))+sizeof(TCHAR);
|
|
szTemp = (LPTSTR)LocalAlloc(LPTR, nTempSize);
|
|
if (!szTemp) return;
|
|
|
|
MultiByteToWideChar(GetACP(), 0,
|
|
pCur->pszInfo, -1,
|
|
szTemp, nTempSize);
|
|
|
|
if (pCur->ckid == FOURCC_ICOP)
|
|
{
|
|
SetDlgItemText(hDlg, IDD_COPYRIGHT, szTemp);
|
|
LocalFree(szTemp);
|
|
continue;
|
|
}
|
|
iIndex = ListBox_AddString(hwndLB, pCur->szInfoDesc);
|
|
if (iIndex != LB_ERR)
|
|
{
|
|
//reassigning wide pointer back into "info" so it will get cleaned up later
|
|
pCur->pszInfo = (LPSTR)szTemp;
|
|
ListBox_SetItemData(hwndLB, iIndex, (LPARAM)pCur->pszInfo);
|
|
}
|
|
}
|
|
SetFocus(hwndLB);
|
|
if (ListBox_SetCurSel(hwndLB, 0) != LB_ERR)
|
|
FORWARD_WM_COMMAND(hDlg, IDD_INFO_NAME, hwndLB, LBN_SELCHANGE, PostMessage);
|
|
}
|
|
|
|
BOOL PASCAL DoDetailsCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
|
|
{
|
|
switch (id)
|
|
{
|
|
|
|
case ID_APPLY:
|
|
return TRUE;
|
|
|
|
case IDOK:
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
break;
|
|
|
|
case ID_INIT:
|
|
{
|
|
PMMPSH pmmpsh = (PMMPSH)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
|
|
if (pmmpsh->hDispBMP)
|
|
{
|
|
HWND hwndDisp = GetDlgItem(hDlg,IDD_DISPFRAME);
|
|
HDC hdc;
|
|
HPALETTE hpalT;
|
|
int i;
|
|
|
|
SendMessage(hwndDisp, (UINT)DF_PM_SETBITMAP, (WPARAM)pmmpsh->hDispBMP,
|
|
(LPARAM)pmmpsh->hPal);
|
|
|
|
/*
|
|
* If realizing the palette causes the palette to change,
|
|
* redraw completely.
|
|
*/
|
|
|
|
hdc = GetDC(hwndDisp);
|
|
hpalT = SelectPalette (hdc, pmmpsh->hPal, FALSE);
|
|
|
|
i = RealizePalette(hdc); /* i == entries that changed */
|
|
|
|
SelectPalette (hdc, hpalT, FALSE);
|
|
ReleaseDC(hwndDisp, hdc);
|
|
|
|
|
|
/* If any palette entries changed, repaint the window. */
|
|
|
|
if (i > 0)
|
|
{
|
|
InvalidateRect(hwndDisp, NULL, TRUE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDD_INFO_NAME:
|
|
if (codeNotify == LBN_SELCHANGE)
|
|
{
|
|
int iIndex = ListBox_GetCurSel(hwndCtl);
|
|
LPTSTR pszInfo = (LPTSTR)ListBox_GetItemData(hwndCtl, iIndex);
|
|
|
|
SetDlgItemText(hDlg, IDD_INFO_VALUE, pszInfo);
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
STATIC void ShowMediaLen(PMMPSH pmmpsh, HWND hwnd)
|
|
{
|
|
TCHAR szBuf[MAXSTR];
|
|
TCHAR szFmt[MAXSTR];
|
|
UINT uMin;
|
|
UINT uSec;
|
|
UINT umSec;
|
|
UINT uLen;
|
|
TCHAR szDecSep[10];
|
|
|
|
uLen = pmmpsh->uLen;
|
|
|
|
if ((!uLen && pmmpsh->iMediaType != MT_WAVE) || (!pmmpsh->pAudioFormatInfo && pmmpsh->iMediaType != MT_MIDI && pmmpsh->iMediaType != MT_AVI && pmmpsh->iMediaType != MT_ASF))
|
|
{
|
|
LoadString(ghInstance, IDS_BADFILE, szBuf, sizeof(szBuf)/sizeof(TCHAR));
|
|
SetWindowText(hwnd, szBuf);
|
|
return;
|
|
}
|
|
uMin = (UINT)(uLen/60000);
|
|
uSec = (UINT)((uLen/1000) % 60);
|
|
umSec = (UINT)(uLen % 1000);
|
|
|
|
//bug 141733, get the local decimal separator
|
|
GetLocaleInfo( GetUserDefaultLCID(), LOCALE_SDECIMAL, szDecSep, sizeof(szDecSep)/sizeof(TCHAR) );
|
|
|
|
if (uMin)
|
|
{
|
|
|
|
LoadString(ghInstance, IDS_MINFMT, szFmt, sizeof(szFmt)/sizeof(TCHAR));
|
|
wsprintf(szBuf, szFmt, uMin, uSec, szDecSep, umSec);
|
|
}
|
|
else
|
|
{
|
|
|
|
LoadString(ghInstance, IDS_SECFMT, szFmt, sizeof(szFmt)/sizeof(TCHAR));
|
|
wsprintf(szBuf, szFmt, uSec, szDecSep, umSec);
|
|
}
|
|
SetWindowText(hwnd, szBuf);
|
|
}
|
|
|
|
|
|
STATIC void ShowMediaFormat(PMMPSH pmmpsh, HWND hDlg)
|
|
{
|
|
switch (pmmpsh->iMediaType)
|
|
{
|
|
case MT_WAVE:
|
|
{
|
|
TCHAR szDesc[MAX_PATH];
|
|
|
|
szDesc[0] = TEXT('\0');
|
|
WaveGetFormatDescription((LPWAVEFORMATEX)pmmpsh->pAudioFormatInfo, szDesc);
|
|
SetDlgItemText(hDlg, IDD_AUDIOFORMAT, szDesc);
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_VIDEOFORMAT));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_VIDEOFORMATLABEL));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_MIDISEQUENCELABEL));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_MIDISEQUENCENAME));
|
|
break;
|
|
}
|
|
case MT_MIDI:
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_AUDIOFORMAT));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_AUDIOFORMATLABEL));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_VIDEOFORMAT));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_VIDEOFORMATLABEL));
|
|
if (pmmpsh->MIDICOPYRIGHTSTR)
|
|
SetDlgItemText(hDlg, IDD_COPYRIGHT, (LPTSTR)pmmpsh->MIDICOPYRIGHTSTR);
|
|
if (pmmpsh->MIDISEQNAMESTR)
|
|
SetDlgItemText(hDlg, IDD_MIDISEQUENCENAME, (LPTSTR)pmmpsh->MIDISEQNAMESTR);
|
|
else
|
|
{
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_MIDISEQUENCELABEL));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_MIDISEQUENCENAME));
|
|
}
|
|
break;
|
|
case MT_AVI:
|
|
{
|
|
TCHAR szDesc[MAX_PATH];
|
|
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_MIDISEQUENCELABEL));
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_MIDISEQUENCENAME));
|
|
|
|
szDesc[0] = TEXT('\0');
|
|
if (pmmpsh->pVideoFormatInfo)
|
|
SetDlgItemText(hDlg, IDD_VIDEOFORMAT, (LPTSTR)pmmpsh->pVideoFormatInfo);
|
|
else
|
|
SetDlgItemText(hDlg, IDD_VIDEOFORMAT, (LPTSTR)szDesc);
|
|
WaveGetFormatDescription((LPWAVEFORMATEX)pmmpsh->pAudioFormatInfo, szDesc);
|
|
SetDlgItemText(hDlg, IDD_AUDIOFORMAT, szDesc);
|
|
break;
|
|
}
|
|
case MT_ASF:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
const static DWORD aFileDetailsIds[] = { // Context Help IDs
|
|
IDD_DISPFRAME, NO_HELP,
|
|
IDD_DISP_ICON, IDH_FPROP_GEN_ICON,
|
|
IDD_FILENAME, IDH_FPROP_GEN_NAME,
|
|
IDD_CRLABEL, IDH_FCAB_MM_COPYRIGHT,
|
|
IDD_COPYRIGHT, IDH_FCAB_MM_COPYRIGHT,
|
|
IDD_LENLABEL, IDH_FCAB_MM_FILELEN,
|
|
IDD_FILELEN, IDH_FCAB_MM_FILELEN,
|
|
IDD_AUDIOFORMATLABEL, IDH_FCAB_MM_AUDIOFORMAT,
|
|
IDD_AUDIOFORMAT, IDH_FCAB_MM_AUDIOFORMAT,
|
|
IDD_MIDISEQUENCELABEL, IDH_FCAB_MM_MIDISEQUENCENAME,
|
|
IDD_MIDISEQUENCENAME, IDH_FCAB_MM_MIDISEQUENCENAME,
|
|
IDD_VIDEOFORMATLABEL, IDH_FCAB_MM_VIDEOFORMAT,
|
|
IDD_VIDEOFORMAT, IDH_FCAB_MM_VIDEOFORMAT,
|
|
IDC_DETAILSINFO_GRP, IDH_FCAB_MM_DETAILSINFO,
|
|
IDC_ITEMSLABEL, IDH_FCAB_MM_DETAILSINFO,
|
|
IDC_DESCLABEL, IDH_FCAB_MM_DETAILSINFO,
|
|
IDD_INFO_NAME, IDH_FCAB_MM_DETAILSINFO,
|
|
IDD_INFO_VALUE, IDH_FCAB_MM_DETAILSINFO,
|
|
|
|
0, 0
|
|
};
|
|
|
|
INT_PTR CALLBACK FileDetailsDlg(HWND hDlg, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
NMHDR FAR *lpnm;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_NOTIFY:
|
|
lpnm = (NMHDR FAR *)lParam;
|
|
switch(lpnm->code)
|
|
{
|
|
case PSN_KILLACTIVE:
|
|
FORWARD_WM_COMMAND(hDlg, IDOK, 0, 0, SendMessage);
|
|
break;
|
|
|
|
case PSN_APPLY:
|
|
FORWARD_WM_COMMAND(hDlg, ID_APPLY, 0, 0, SendMessage);
|
|
break;
|
|
|
|
case PSN_SETACTIVE:
|
|
FORWARD_WM_COMMAND(hDlg, ID_INIT, 0, 0, SendMessage);
|
|
break;
|
|
|
|
case PSN_RESET:
|
|
FORWARD_WM_COMMAND(hDlg, IDCANCEL, 0, 0, SendMessage);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
PMMPSH pmmpsh = (PMMPSH)(((LPPROPSHEETPAGE)lParam)->lParam);
|
|
TCHAR szFile[MAX_PATH];
|
|
HANDLE hDib = NULL;
|
|
HCURSOR hCursor;
|
|
|
|
hCursor = SetCursor(LoadCursor(NULL,IDC_WAIT));
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)pmmpsh);
|
|
|
|
if (!pmmpsh->pInfoList)
|
|
{
|
|
hDib = GetRiffAll(pmmpsh);
|
|
}
|
|
|
|
if (!hDib)
|
|
break;
|
|
|
|
pmmpsh->hPal = bmfCreateDIBPalette(hDib);
|
|
pmmpsh->hDispBMP = bmfBitmapFromDIB(hDib, pmmpsh->hPal);
|
|
if (hDib)
|
|
{
|
|
GlobalUnlock(hDib);
|
|
hDib = GlobalFree(hDib);
|
|
}
|
|
if (!pmmpsh->hDispBMP)
|
|
{
|
|
int iIconID;
|
|
|
|
switch (pmmpsh->iMediaType)
|
|
{
|
|
case MT_WAVE:
|
|
iIconID = IDI_DWAVE;
|
|
break;
|
|
case MT_MIDI:
|
|
iIconID = IDI_DMIDI;
|
|
break;
|
|
case MT_AVI:
|
|
case MT_ASF:
|
|
iIconID = IDI_DVIDEO;
|
|
break;
|
|
}
|
|
DestroyWindow(GetDlgItem(hDlg,IDD_DISPFRAME));
|
|
pmmpsh->hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(iIconID));
|
|
Static_SetIcon(GetDlgItem(hDlg, IDD_DISP_ICON), pmmpsh->hIcon);
|
|
}
|
|
else
|
|
{
|
|
DestroyWindow(GetDlgItem(hDlg,IDD_DISP_ICON));
|
|
//SendDlgItemMessage(hDlg, (int)IDD_DISPFRAME, (UINT)DF_PM_SETBITMAP, (WPARAM)pmmpsh->hDispBMP,
|
|
// (LPARAM)pmmpsh->hPal);
|
|
}
|
|
|
|
lstrcpy(szFile, pmmpsh->pszFileObj);
|
|
NiceName(szFile, TRUE);
|
|
SetDlgItemText(hDlg, IDD_FILENAME, szFile);
|
|
|
|
ShowMediaLen(pmmpsh, GetDlgItem(hDlg, IDD_FILELEN));
|
|
ShowInfoList(pmmpsh, hDlg);
|
|
ShowMediaFormat(pmmpsh, hDlg);
|
|
SetCursor(hCursor);
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
PMMPSH pmmpsh = (PMMPSH)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
if (pmmpsh->hDispBMP)
|
|
DeleteObject(pmmpsh->hDispBMP);
|
|
if (pmmpsh->hIcon)
|
|
DestroyIcon(pmmpsh->hIcon);
|
|
if (pmmpsh->hPal)
|
|
DeleteObject(pmmpsh->hPal);
|
|
if (pmmpsh->pAudioFormatInfo)
|
|
LocalFree((HLOCAL)pmmpsh->pAudioFormatInfo);
|
|
if (pmmpsh->pVideoFormatInfo)
|
|
LocalFree((HLOCAL)pmmpsh->pVideoFormatInfo);
|
|
break;
|
|
}
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND)wParam, gszWindowsHlp, HELP_CONTEXTMENU,
|
|
(UINT_PTR)(LPTSTR)aFileDetailsIds);
|
|
return TRUE;
|
|
|
|
case WM_HELP:
|
|
WinHelp(((LPHELPINFO)lParam)->hItemHandle, gszWindowsHlp, HELP_WM_HELP
|
|
, (UINT_PTR)(LPTSTR)aFileDetailsIds);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
HANDLE_WM_COMMAND(hDlg, wParam, lParam, DoDetailsCommand);
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static DWORD aPreviewIds[] = { // Context Help IDs
|
|
0, IDH_FCAB_MM_PREVIEW_CONTROL,
|
|
IDD_DISP_ICON, IDH_FPROP_GEN_ICON,
|
|
IDD_FILENAME, IDH_FPROP_GEN_NAME,
|
|
|
|
0, 0
|
|
};
|
|
|
|
INT_PTR CALLBACK PreviewDlg(HWND hDlg, UINT uMsg, WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
static BOOL fLoadedVFW;
|
|
static HICON hIcon;
|
|
switch (uMsg)
|
|
{
|
|
case WM_NOTIFY:
|
|
{
|
|
NMHDR FAR *lpnm;
|
|
|
|
lpnm = (NMHDR FAR *)lParam;
|
|
switch(lpnm->code)
|
|
{
|
|
case PSN_KILLACTIVE:
|
|
{
|
|
HWND hwndMCI = (HWND)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
DPF("***PSN_KILLACTIVE***\r\n");
|
|
if (IsWindow(hwndMCI))
|
|
MCIWndStop(hwndMCI);
|
|
break;
|
|
}
|
|
|
|
case PSN_APPLY:
|
|
DPF("***PSN_APPLY***\r\n");
|
|
return TRUE;
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_INITDIALOG:
|
|
{
|
|
PMMPSH pmmpsh = (PMMPSH)(((LPPROPSHEETPAGE)lParam)->lParam);
|
|
HCURSOR hCursor;
|
|
HWND hwndMCI;
|
|
HWND hwndTitle;
|
|
RECT rcWnd;
|
|
RECT rcDlg;
|
|
TCHAR szFile[MAX_PATH];
|
|
TCHAR szTitle[MAXSTR];
|
|
TCHAR szTmp[MAXSTR];
|
|
#ifndef DEBUG_BUILT_LINKED
|
|
FN_MCIWNDCREATE fnMCIWndCreate;
|
|
#endif
|
|
|
|
hCursor = SetCursor(LoadCursor(NULL,IDC_WAIT));
|
|
lstrcpy(szFile, pmmpsh->pszFileObj);
|
|
NiceName(szFile, TRUE);
|
|
LoadString(ghInstance, IDS_PREVIEWOF, szTmp, sizeof(szTmp)/sizeof(TCHAR));
|
|
wsprintf(szTitle, szTmp, szFile);
|
|
hwndTitle = GetDlgItem(hDlg, IDD_FILENAME);
|
|
SetWindowText(hwndTitle, szTitle);
|
|
|
|
fLoadedVFW = FALSE;
|
|
if (!LoadVFW())
|
|
{
|
|
DPF("****Load VFW failed**\r\n");
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
fLoadedVFW = TRUE;
|
|
#ifndef DEBUG_BUILT_LINKED
|
|
fnMCIWndCreate = (FN_MCIWNDCREATE)MCIWndCreateW;
|
|
hwndMCI = fnMCIWndCreate(hDlg, ghInstance, (DWORD)MCIWNDF_NOMENU, (LPCTSTR)pmmpsh->pszFileObj);
|
|
#else
|
|
hwndMCI = MCIWndCreateW(hDlg, ghInstance, (DWORD)MCIWNDF_NOMENU, (LPCTSTR)pmmpsh->pszFileObj);
|
|
#endif
|
|
aPreviewIds[0] = GetDlgCtrlID(hwndMCI);
|
|
GetWindowRect(hwndMCI, &rcWnd);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rcWnd, 2);
|
|
GetWindowRect(hDlg, &rcDlg);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rcDlg, 2);
|
|
hIcon = NULL;
|
|
switch (pmmpsh->iMediaType)
|
|
{
|
|
case MT_WAVE:
|
|
case MT_MIDI:
|
|
{
|
|
int ircWndTop;
|
|
|
|
ircWndTop = (int)((rcDlg.bottom - rcDlg.top)/2) - 50;
|
|
rcWnd.top += ircWndTop;
|
|
rcWnd.bottom += ircWndTop;
|
|
rcWnd.left = 20;
|
|
rcWnd.right = rcDlg.right - 20;
|
|
|
|
MoveWindow(hwndMCI, rcWnd.left, rcWnd.top, (rcWnd.right - rcWnd.left),
|
|
(rcWnd.bottom - rcWnd.top), FALSE);
|
|
GetWindowRect(hwndTitle, &rcWnd);
|
|
MapWindowPoints(NULL, hDlg, (LPPOINT)&rcWnd, 2);
|
|
OffsetRect(&rcWnd, 52, 36);
|
|
MoveWindow(hwndTitle, rcWnd.left, rcWnd.top, (rcWnd.right - rcWnd.left),
|
|
(rcWnd.bottom - rcWnd.top), FALSE);
|
|
hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_DWAVE+pmmpsh->iMediaType-1));
|
|
Static_SetIcon(GetDlgItem(hDlg, IDD_DISP_ICON),hIcon);
|
|
|
|
break;
|
|
}
|
|
case MT_AVI:
|
|
{
|
|
int iDlgHt = rcDlg.bottom - rcDlg.top -15; //15 for the title
|
|
int iDlgWth = rcDlg.right - rcDlg.left;
|
|
int iWndHt = rcWnd.bottom - rcWnd.top;
|
|
int iWndWth = rcWnd.right - rcWnd.left;
|
|
|
|
DestroyWindow(GetDlgItem(hDlg, IDD_DISP_ICON));
|
|
if (iWndWth < iDlgWth && iWndHt < iDlgHt)
|
|
{
|
|
int ixOff = (int)((iDlgWth - iWndWth)/2);
|
|
int iyOff = (int)((iDlgHt - iWndHt)/2) + 15;
|
|
|
|
OffsetRect(&rcWnd, ixOff, iyOff);
|
|
MoveWindow(hwndMCI, rcWnd.left, rcWnd.top, (rcWnd.right - rcWnd.left),
|
|
(rcWnd.bottom - rcWnd.top), FALSE);
|
|
}
|
|
else
|
|
{
|
|
int ixExcess = iWndWth - iDlgWth;
|
|
int iyExcess = iWndHt - (iDlgHt - 15); //Take another 15 off
|
|
int ixOff;
|
|
int iyOff;
|
|
RECT rcSource;
|
|
RECT rcDest;
|
|
RECT rcDestWnd;
|
|
|
|
MCIWndGetDest(hwndMCI, &rcSource);
|
|
//DPF("The Video Window is too big: SHRINKING\r\nrcSource = %d,%d,%d%d ** rcWnd=%d,%d,%d,%d ** rcDlg=%d,%d,%d,%d\r\n",
|
|
// rcSource.left,rcSource.top,rcSource.right,rcSource.bottom,
|
|
// rcWnd.left,rcWnd.top,rcWnd.right,rcWnd.bottom,
|
|
// rcDlg.left,rcDlg.top,rcDlg.right,rcDlg.bottom);
|
|
rcDest.top = rcSource.top; // new boundaries
|
|
rcDest.left = rcSource.left;
|
|
if (ixExcess > iyExcess)
|
|
{
|
|
rcDest.right = rcSource.left +
|
|
(((rcSource.right - rcSource.left)*(iDlgWth - 20))/iWndWth);
|
|
rcDest.bottom = rcSource.top +
|
|
(((rcSource.bottom - rcSource.top)*(iDlgWth - 20))/iWndWth);
|
|
//DPF("rcDest = %d,%d,%d,%d\r\n",rcDest.left,rcDest.top,rcDest.right,rcDest.bottom);
|
|
}
|
|
else
|
|
{
|
|
rcDest.right = rcSource.left +
|
|
(((rcSource.right - rcSource.left)*(iDlgHt - 20))/iWndHt);
|
|
rcDest.bottom = rcSource.top +
|
|
(((rcSource.bottom - rcSource.top)*(iDlgHt - 20))/iWndHt);
|
|
}
|
|
rcDestWnd.top = rcWnd.top;
|
|
rcDestWnd.left = rcWnd.left;
|
|
rcDestWnd.right = rcWnd.left + (rcDest.right - rcDest.left);
|
|
rcDestWnd.bottom = rcWnd.top + (rcDest.bottom - rcDest.top)
|
|
+ (iWndHt - (rcSource.bottom - rcSource.top));
|
|
//DPF("rcDestWnd = %d,%d,%d,%d\r\n",rcDestWnd.left,rcDestWnd.top,rcDestWnd.right,rcDestWnd.bottom);
|
|
|
|
ixOff = (int)((iDlgWth - (rcDestWnd.right - rcDestWnd.left))/2);
|
|
iyOff = (int)((iDlgHt - (rcDestWnd.bottom - rcDestWnd.top))/2) + 15;
|
|
//DPF("ixOff = %, iyOff = %d\r\n", ixOff, iyOff);
|
|
OffsetRect(&rcDestWnd, ixOff, iyOff);
|
|
MCIWndPutDest(hwndMCI, &rcDest);
|
|
MoveWindow(hwndMCI, rcDestWnd.left, rcDestWnd.top, (rcDestWnd.right - rcDestWnd.left),
|
|
(rcDestWnd.bottom - rcDestWnd.top), FALSE);
|
|
|
|
}
|
|
break;
|
|
|
|
case MT_ASF:
|
|
break;
|
|
}
|
|
}
|
|
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)hwndMCI);
|
|
SetCursor(hCursor);
|
|
break;
|
|
}
|
|
|
|
case WM_CLOSE:
|
|
DPF("***WM_CLOSE***\r\n");
|
|
break;
|
|
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
HWND hwndMCI = (HWND)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
DPF("***WM_DESTROY***\r\n");
|
|
if (hIcon)
|
|
{
|
|
DestroyIcon(hIcon);
|
|
hIcon = NULL;
|
|
}
|
|
if (IsWindow(hwndMCI))
|
|
MCIWndDestroy(hwndMCI);
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)NULL);
|
|
|
|
if (!fLoadedVFW)
|
|
break;
|
|
if (!FreeVFW())
|
|
{
|
|
DPF("****Free VFW failed**\r\n");
|
|
ASSERT(FALSE);
|
|
}
|
|
fLoadedVFW = FALSE;
|
|
break;
|
|
}
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND)wParam, gszWindowsHlp, HELP_CONTEXTMENU,
|
|
(UINT_PTR)(LPTSTR)aPreviewIds);
|
|
return TRUE;
|
|
|
|
case WM_HELP:
|
|
WinHelp(((LPHELPINFO)lParam)->hItemHandle, gszWindowsHlp, HELP_WM_HELP
|
|
, (UINT_PTR)(LPTSTR)aPreviewIds);
|
|
return TRUE;
|
|
|
|
case WM_QUERYNEWPALETTE:
|
|
case WM_PALETTECHANGED:
|
|
{
|
|
HWND hwndMCI = (HWND)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
SendMessage(hwndMCI, uMsg, wParam, lParam);
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// mmse IUnknown base member functions
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IUnknown::QueryInterface
|
|
|
|
Returns: standard
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP mmpsh_QueryInterface(
|
|
LPUNKNOWN punk,
|
|
REFIID riid,
|
|
LPVOID FAR* ppvOut)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, sei, punk);
|
|
HRESULT hres = ResultFromScode(E_NOINTERFACE);
|
|
*ppvOut = NULL;
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IShellExtInit))
|
|
{
|
|
// We use the sei field as our IUnknown as well
|
|
*ppvOut = &this->sei;
|
|
this->cRef++;
|
|
hres = NOERROR;
|
|
}
|
|
else if (IsEqualIID(riid, &IID_IShellPropSheetExt))
|
|
{
|
|
(LPSHELLPROPSHEETEXT)*ppvOut = &this->pse;
|
|
this->cRef++;
|
|
hres = NOERROR;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IUnknown::AddRef
|
|
|
|
Returns: new reference count
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP_(UINT) mmpsh_AddRef(
|
|
LPUNKNOWN punk)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, sei, punk);
|
|
|
|
return ++this->cRef;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IUnknown::Release
|
|
|
|
Returns: new reference count
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP_(UINT) mmpsh_Release(
|
|
LPUNKNOWN punk)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, sei, punk);
|
|
|
|
if (--this->cRef)
|
|
{
|
|
return this->cRef;
|
|
}
|
|
|
|
DPF_T("*^*^*^*^*^*^*^*^*^MMPSH nuked , RefCnt = %d *^*^*^*^ \r\n", (g_cRef - 1));
|
|
if (this->pdtobj)
|
|
{
|
|
this->pdtobj->lpVtbl->Release(this->pdtobj);
|
|
}
|
|
|
|
if (this->pszFileObj)
|
|
{
|
|
LocalFree((HLOCAL)this->pszFileObj);
|
|
}
|
|
ReleaseInfoList(this);
|
|
|
|
LocalFree((HLOCAL)this);
|
|
--g_cRef;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellExtInit::QueryInterface
|
|
|
|
Returns: standard
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP mmpsh_SEI_QueryInterface(
|
|
LPSHELLEXTINIT psei,
|
|
REFIID riid,
|
|
LPVOID FAR* ppvOut)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, sei, psei);
|
|
|
|
return mmpsh_QueryInterface((LPUNKNOWN)&this->sei, riid, ppvOut);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellExtInit::AddRef
|
|
|
|
Returns: new reference count
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP_(UINT) mmpsh_SEI_AddRef(
|
|
LPSHELLEXTINIT psei)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, sei, psei);
|
|
|
|
return mmpsh_AddRef((LPUNKNOWN)&this->sei);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellExtInit::Release
|
|
|
|
Returns: new reference count
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP_(UINT) mmpsh_SEI_Release(
|
|
LPSHELLEXTINIT psei)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, sei, psei);
|
|
return mmpsh_Release((LPUNKNOWN)&this->sei);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: MMPSHReleaseStgMedium
|
|
|
|
Returns: NOERROR
|
|
Cond: --
|
|
*/
|
|
HRESULT MMPSHReleaseStgMedium(LPSTGMEDIUM pmedium)
|
|
{
|
|
//
|
|
// Double-check pUnkForRelease in case we're not supposed to
|
|
// release the medium.
|
|
//
|
|
if (NULL == pmedium->pUnkForRelease)
|
|
{
|
|
switch(pmedium->tymed)
|
|
{
|
|
case TYMED_HGLOBAL:
|
|
GlobalFree(pmedium->hGlobal);
|
|
break;
|
|
|
|
case TYMED_ISTORAGE:
|
|
pmedium->pstg->lpVtbl->Release(pmedium->pstg);
|
|
break;
|
|
|
|
case TYMED_ISTREAM:
|
|
pmedium->pstm->lpVtbl->Release(pmedium->pstm);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE); // unknown type
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellExtInit::Initialize
|
|
|
|
Returns: noerror
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP mmpsh_SEI_Initialize(
|
|
LPSHELLEXTINIT psei,
|
|
LPCITEMIDLIST pidlObj,
|
|
LPDATAOBJECT pdtobj,
|
|
HKEY hkeyProgID)
|
|
{
|
|
HRESULT hres = NOERROR;
|
|
PMMPSH this = IToClass(mmpsh, sei, psei);
|
|
DPF("mmpsh_SEI_Initialize called\n");
|
|
|
|
if (pdtobj)
|
|
{
|
|
STGMEDIUM medium;
|
|
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
if (this->pdtobj)
|
|
{
|
|
this->pdtobj->lpVtbl->Release(this->pdtobj);
|
|
}
|
|
this->pdtobj = pdtobj;
|
|
pdtobj->lpVtbl->AddRef(pdtobj);
|
|
|
|
hres = pdtobj->lpVtbl->GetData(pdtobj, &fmte, &medium);
|
|
if(SUCCEEDED(hres))
|
|
{
|
|
if (DragQueryFile(medium.hGlobal, (UINT)-1, NULL, 0))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
int iIndex;
|
|
DWORD dwSize = 0;
|
|
|
|
szPath[0] = '\0';
|
|
|
|
DragQueryFile(medium.hGlobal, 0, szPath, sizeof(szPath)/sizeof(TCHAR));
|
|
|
|
dwSize = mmpshGetFileSize(szPath);
|
|
if (dwSize != 0)
|
|
{
|
|
iIndex = lstrlen(szPath) - 4;
|
|
if (!lstrcmpi((LPTSTR)(szPath+iIndex), cszWavExt))
|
|
this->iMediaType = MT_WAVE;
|
|
else if (!lstrcmpi((LPTSTR)(szPath+iIndex), cszMIDIExt))
|
|
this->iMediaType = MT_MIDI;
|
|
else if (!lstrcmpi((LPTSTR)(szPath+iIndex), cszRMIExt))
|
|
this->iMediaType = MT_MIDI;
|
|
else if (!lstrcmpi((LPTSTR)(szPath+iIndex), cszAVIExt))
|
|
this->iMediaType = MT_AVI;
|
|
else if (!lstrcmpi((LPTSTR)(szPath+iIndex), cszASFExt))
|
|
this->iMediaType = MT_ASF;
|
|
else
|
|
this->iMediaType = MT_ERROR;
|
|
|
|
if (!this->pszFileObj || lstrcmpi(this->pszFileObj, szPath))
|
|
{
|
|
if (this->pszFileObj)
|
|
LocalFree((HLOCAL)this->pszFileObj);
|
|
ReleaseInfoList(this);
|
|
if (this->iMediaType)
|
|
{
|
|
this->pszFileObj = (LPTSTR)LocalAlloc(LPTR, (lstrlen(szPath)*sizeof(TCHAR))+sizeof(TCHAR));
|
|
if (this->pszFileObj) lstrcpy(this->pszFileObj , szPath);
|
|
}
|
|
else
|
|
hres = ResultFromScode(E_FAIL);
|
|
}
|
|
}
|
|
else
|
|
hres = ResultFromScode(E_FAIL);
|
|
}
|
|
//
|
|
// Release STGMEDIUM if we're responsible for doing that.
|
|
//
|
|
if (NULL == medium.pUnkForRelease)
|
|
MMPSHReleaseStgMedium(&medium);
|
|
}
|
|
else
|
|
return hres;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellPropSheetExt::QueryInterface
|
|
|
|
Returns: standard
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP mmpsh_PSE_QueryInterface(
|
|
LPSHELLPROPSHEETEXT ppse,
|
|
REFIID riid,
|
|
LPVOID FAR* ppvOut)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, pse, ppse);
|
|
|
|
return mmpsh_QueryInterface((LPUNKNOWN)&this->sei, riid, ppvOut);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellPropSheetExt::AddRef
|
|
|
|
Returns: new reference count
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP_(UINT) mmpsh_PSE_AddRef(
|
|
LPSHELLPROPSHEETEXT ppse)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, pse, ppse);
|
|
|
|
return mmpsh_AddRef((LPUNKNOWN)&this->sei);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellPropSheetExt::Release
|
|
|
|
Returns: new reference count
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP_(UINT) mmpsh_PSE_Release(
|
|
LPSHELLPROPSHEETEXT ppse)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, pse, ppse);
|
|
return mmpsh_Release((LPUNKNOWN)&this->sei);
|
|
}
|
|
|
|
/*==========================================================================*/
|
|
UINT CALLBACK DetailsPageCallback(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
LPPROPSHEETPAGE ppsp)
|
|
{
|
|
if (uMsg == PSPCB_RELEASE)
|
|
if (((PMMPSH)(ppsp->lParam))->pse.lpVtbl)
|
|
((PMMPSH)(ppsp->lParam))->pse.lpVtbl->Release(&(((PMMPSH)(ppsp->lParam))->pse));
|
|
else
|
|
{
|
|
LocalFree((HLOCAL)((PMMPSH)(ppsp->lParam))->pszFileObj);
|
|
LocalFree((HLOCAL)ppsp->lParam);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
BOOL AddDetailsPage(
|
|
LPTSTR pszTitle,
|
|
LPFNADDPROPSHEETPAGE lpfnAddPropSheetPage,
|
|
LPARAM lDlgParam,
|
|
LPARAM lParam)
|
|
{
|
|
PROPSHEETPAGE psp;
|
|
HPROPSHEETPAGE hpsp;
|
|
|
|
psp.dwSize = sizeof(PROPSHEETPAGE);
|
|
psp.dwFlags = PSP_USETITLE | PSP_USECALLBACK;
|
|
psp.hInstance = ghInstance;
|
|
psp.pszTemplate = MAKEINTRESOURCE(DLG_FILE_DETAILS);
|
|
psp.pszIcon = NULL;
|
|
psp.pszTitle = pszTitle;
|
|
psp.pfnDlgProc = FileDetailsDlg;
|
|
psp.lParam = lDlgParam;
|
|
psp.pfnCallback = DetailsPageCallback;
|
|
psp.pcRefParent = NULL;
|
|
if (hpsp = CreatePropertySheetPage(&psp))
|
|
{
|
|
if (lpfnAddPropSheetPage(hpsp, lParam))
|
|
return TRUE;
|
|
DestroyPropertySheetPage(hpsp);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
UINT CALLBACK PreviewPageCallback(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
LPPROPSHEETPAGE ppsp)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
BOOL AddPreviewPage(
|
|
LPTSTR pszTitle,
|
|
LPFNADDPROPSHEETPAGE lpfnAddPropSheetPage,
|
|
LPARAM lDlgParam,
|
|
LPARAM lParam)
|
|
{
|
|
PROPSHEETPAGE psp;
|
|
HPROPSHEETPAGE hpsp;
|
|
|
|
psp.dwSize = sizeof(PROPSHEETPAGE);
|
|
psp.dwFlags = PSP_USETITLE | PSP_USECALLBACK;
|
|
psp.hInstance = ghInstance;
|
|
psp.pszTemplate = MAKEINTRESOURCE(PREVIEW_DLG);
|
|
psp.pszIcon = NULL;
|
|
psp.pszTitle = pszTitle;
|
|
psp.pfnDlgProc = PreviewDlg;
|
|
psp.lParam = lDlgParam;
|
|
psp.pfnCallback = PreviewPageCallback;
|
|
psp.pcRefParent = NULL;
|
|
if (hpsp = CreatePropertySheetPage(&psp))
|
|
{
|
|
if (lpfnAddPropSheetPage(hpsp, lParam))
|
|
return TRUE;
|
|
DestroyPropertySheetPage(hpsp);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellPropSheetExt::AddPages
|
|
|
|
Returns: NOERROR
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP mmpsh_PSE_AddPages(
|
|
LPSHELLPROPSHEETEXT ppse,
|
|
LPFNADDPROPSHEETPAGE lpfnAddPage,
|
|
LPARAM lParam)
|
|
{
|
|
PMMPSH this = IToClass(mmpsh, pse, ppse);
|
|
/* BOOL fAddPreview = FALSE;
|
|
|
|
LoadString(ghInstance, IDS_DETAILS, szDetailsTab, sizeof(szDetailsTab)/sizeof(TCHAR));
|
|
RegSndCntrlClass((LPCTSTR)DISPFRAMCLASS);
|
|
AddDetailsPage(szDetailsTab,lpfnAddPage,(LPARAM)this, lParam);
|
|
switch (this->iMediaType)
|
|
{
|
|
case MT_AVI:
|
|
fAddPreview = TRUE;
|
|
break;
|
|
case MT_WAVE:
|
|
if (waveOutGetNumDevs() > 0)
|
|
fAddPreview = TRUE;
|
|
break;
|
|
case MT_MIDI:
|
|
if (midiOutGetNumDevs() > 0)
|
|
fAddPreview = TRUE;
|
|
break;
|
|
}
|
|
if (fAddPreview)
|
|
{
|
|
LoadString(ghInstance, IDS_PREVIEW, szPreviewTab, sizeof(szPreviewTab)/sizeof(TCHAR));
|
|
AddPreviewPage(szPreviewTab,lpfnAddPage,(LPARAM)this, lParam);
|
|
} */
|
|
ppse->lpVtbl->AddRef(ppse);
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: IShellPropSheetExt::ReplacePage
|
|
|
|
Returns: E_NOTIMPL
|
|
Cond: --
|
|
*/
|
|
STDMETHODIMP mmpsh_PSE_ReplacePage(
|
|
LPSHELLPROPSHEETEXT ppse,
|
|
UINT uPageID,
|
|
LPFNADDPROPSHEETPAGE lpfnReplaceWith,
|
|
LPARAM lParam)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
|
|
IShellExtInitVtbl c_mmpshSEIVtbl =
|
|
{
|
|
mmpsh_SEI_QueryInterface,
|
|
mmpsh_SEI_AddRef,
|
|
mmpsh_SEI_Release,
|
|
mmpsh_SEI_Initialize
|
|
};
|
|
|
|
IShellPropSheetExtVtbl c_mmpshPSEVtbl =
|
|
{
|
|
mmpsh_PSE_QueryInterface,
|
|
mmpsh_PSE_AddRef,
|
|
mmpsh_PSE_Release,
|
|
mmpsh_PSE_AddPages,
|
|
mmpsh_PSE_ReplacePage
|
|
} ;
|
|
|
|
|
|
HRESULT CALLBACK mmpsh_CreatePSHInstance(
|
|
LPUNKNOWN punkOuter,
|
|
REFIID riid,
|
|
LPVOID FAR* ppvOut)
|
|
{
|
|
HRESULT hres;
|
|
PMMPSH this;
|
|
|
|
DPF_T("*^*^*^*^*^*^*^*^mmpsh_CreatePSHInstance*^*^*^*^*^*^*^*^\r\n");
|
|
|
|
// The handler does not support aggregation.
|
|
if (punkOuter)
|
|
{
|
|
hres = ResultFromScode(CLASS_E_NOAGGREGATION);
|
|
goto Leave;
|
|
}
|
|
|
|
this = LocalAlloc(LPTR, sizeof(*this));
|
|
if (!this)
|
|
{
|
|
hres = ResultFromScode(E_OUTOFMEMORY);
|
|
goto Leave;
|
|
}
|
|
this->sei.lpVtbl = &c_mmpshSEIVtbl;
|
|
this->pse.lpVtbl = &c_mmpshPSEVtbl;
|
|
this->cRef = 1;
|
|
|
|
++g_cRef;
|
|
|
|
// Note that the Release member will free the object, if
|
|
// QueryInterface failed.
|
|
hres = this->sei.lpVtbl->QueryInterface(&this->sei, riid, ppvOut);
|
|
this->sei.lpVtbl->Release(&this->sei);
|
|
|
|
Leave:
|
|
|
|
return hres; // S_OK or E_NOINTERFACE
|
|
}
|
|
|
|
BOOL mmpsh_ShowFileDetails(LPTSTR pszCaption,
|
|
HWND hwndParent,
|
|
LPTSTR pszFile,
|
|
short iMediaType)
|
|
{
|
|
PMMPSH pmmpsh;
|
|
TCHAR szTabName[64];
|
|
|
|
pmmpsh = (PMMPSH)LocalAlloc(LPTR, sizeof(*pmmpsh));
|
|
|
|
if (!pmmpsh)
|
|
return FALSE;
|
|
|
|
pmmpsh->pszFileObj = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pszFile)*sizeof(TCHAR))+sizeof(TCHAR));
|
|
|
|
if (!pmmpsh->pszFileObj)
|
|
{
|
|
LocalFree((HLOCAL)pmmpsh);
|
|
return FALSE;
|
|
}
|
|
|
|
lstrcpy(pmmpsh->pszFileObj , pszFile);
|
|
pmmpsh->iMediaType = iMediaType;
|
|
LoadString(ghInstance, IDS_DETAILS, szTabName, sizeof(szTabName)/sizeof(TCHAR));
|
|
ShowPropSheet(szTabName,FileDetailsDlg,DLG_FILE_DETAILS,hwndParent,pszCaption,(LPARAM)pmmpsh);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL ResolveLink(LPTSTR szPath, LPTSTR szResolved, LONG cbSize)
|
|
{
|
|
IShellLink *psl = NULL;
|
|
HRESULT hres;
|
|
|
|
hres = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, &IID_IShellLink, &psl);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
WCHAR wszPath[MAX_PATH];
|
|
IPersistFile *ppf;
|
|
|
|
psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf);
|
|
if (ppf)
|
|
{
|
|
|
|
wcscpy(wszPath, szPath);
|
|
hres = ppf->lpVtbl->Load(ppf, wszPath, 0);
|
|
ppf->lpVtbl->Release(ppf);
|
|
|
|
if (FAILED(hres))
|
|
{
|
|
psl->lpVtbl->Release(psl);
|
|
psl = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
psl = NULL;
|
|
}
|
|
}
|
|
if (psl)
|
|
{
|
|
// this reslve could fail.. should we really do NOUI?
|
|
psl->lpVtbl->Resolve(psl, NULL, SLR_NO_UI);
|
|
psl->lpVtbl->GetPath(psl, szResolved, cbSize, NULL,
|
|
SLGP_SHORTPATH);
|
|
psl->lpVtbl->Release(psl);
|
|
}
|
|
if (SUCCEEDED(hres))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// EXPORTED API
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Standard shell entry-point
|
|
|
|
Returns: standard
|
|
Cond: --
|
|
*/
|
|
STDAPI DllGetClassObject(
|
|
REFCLSID rclsid,
|
|
REFIID riid,
|
|
LPVOID FAR* ppv)
|
|
{
|
|
|
|
// We are supposed return the class object for this class. Instead
|
|
// of fully implementing it in this DLL, we just call a helper
|
|
// function in the shell DLL which creates a default class factory
|
|
// object for us. When its CreateInstance member is called, it
|
|
// will call back our create instance function.
|
|
//
|
|
|
|
if (IsEqualIID(rclsid, &CLSID_mmsePropSheetHandler))
|
|
{
|
|
return SHCreateDefClassObject(
|
|
riid, // Interface ID
|
|
ppv, // Non-null to aggregate
|
|
mmpsh_CreatePSHInstance, // Callback function
|
|
&g_cRef, // Reference count of this DLL
|
|
&IID_IShellExtInit); // Init interface
|
|
}
|
|
return ResultFromScode(REGDB_E_CLASSNOTREG);
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// STDAPI DllCanUnLoadNow()
|
|
//
|
|
// This function is called by shell
|
|
//
|
|
//****************************************************************************
|
|
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (0 == g_cRef)
|
|
{
|
|
DPF("DllCanUnloadNow says OK (Ref=%d)",
|
|
g_cRef);
|
|
|
|
hr = ResultFromScode(S_OK);
|
|
}
|
|
else
|
|
{
|
|
DPF("DllCanUnloadNow says FALSE (Ref=%d)",
|
|
g_cRef);
|
|
|
|
hr = ResultFromScode(S_FALSE);
|
|
}
|
|
return hr;
|
|
}
|
|
|