610 lines
16 KiB
C
610 lines
16 KiB
C
/****************************************************************************
|
|
*
|
|
* MODULE : RIFFDISP.C
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <win32.h>
|
|
#include <mmsystem.h>
|
|
#include <commdlg.h>
|
|
#include <vfw.h>
|
|
#include "riffdisp.h"
|
|
|
|
static HWND hwndPreview;
|
|
static HANDLE hdibPreview;
|
|
static char achPreview[MAX_PATH];
|
|
static HFONT hfontPreview;
|
|
|
|
static HDRAWDIB hdd;
|
|
|
|
#define GetHInstance() (HINSTANCE)(SELECTOROF((LPVOID)&hwndPreview))
|
|
|
|
#define DibSizeImage(lpbi) (\
|
|
(DWORD)(UINT)((((int)lpbi->biBitCount*(int)lpbi->biWidth+31)&~31)>>3) * \
|
|
(DWORD)(UINT)lpbi->biHeight)
|
|
|
|
#define DibSize(lpbi) \
|
|
(lpbi->biSize + ((int)lpbi->biClrUsed * sizeof(RGBQUAD)) + lpbi->biSizeImage)
|
|
|
|
#define DibNumColors(lpbi) \
|
|
(lpbi->biBitCount <= 8 ? (1 << (int)lpbi->biBitCount) : 0)
|
|
|
|
/***************************************************************************
|
|
*
|
|
****************************************************************************/
|
|
|
|
//#define FOURCC_RIFF mmioFOURCC('R','I','F','F')
|
|
#define FOURCC_AVI mmioFOURCC('A','V','I',' ')
|
|
#define FOURCC_INFO mmioFOURCC('I','N','F','O')
|
|
#define FOURCC_DISP mmioFOURCC('D','I','S','P')
|
|
#define FOURCC_INAM mmioFOURCC('I','N','A','M')
|
|
#define FOURCC_ISBJ mmioFOURCC('I','S','B','J')
|
|
|
|
BOOL PreviewOpen(HWND hwnd);
|
|
BOOL PreviewFile(HWND hwnd, LPSTR szFile);
|
|
BOOL PreviewPaint(HWND hwnd);
|
|
BOOL PreviewClose(HWND hwnd);
|
|
|
|
HANDLE ReadDisp(LPSTR lpszFile, int cf, LPSTR pv, int iLen);
|
|
HANDLE ReadInfo(LPSTR lpszFile, FOURCC fcc, LPSTR pv, int iLen);
|
|
HANDLE GetRiffDisp(LPSTR lpszFile, LPSTR szText, int iLen);
|
|
|
|
/***************************************************************************
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL PreviewOpen(HWND hwnd)
|
|
{
|
|
LOGFONT lf;
|
|
|
|
if (hwndPreview)
|
|
return FALSE;
|
|
|
|
hwndPreview = hwnd;
|
|
|
|
hdd = DrawDibOpen();
|
|
|
|
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (LPVOID)&lf, 0);
|
|
hfontPreview = CreateFontIndirect(&lf);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL PreviewClose(HWND hwnd)
|
|
{
|
|
if (hwndPreview != hwnd)
|
|
return FALSE;
|
|
|
|
if (hdibPreview)
|
|
GlobalFree(hdibPreview);
|
|
|
|
if (hfontPreview)
|
|
DeleteObject(hfontPreview);
|
|
|
|
if (hdd)
|
|
DrawDibClose(hdd);
|
|
|
|
achPreview[0] = 0;
|
|
hdd = NULL;
|
|
hwndPreview = NULL;
|
|
hdibPreview = NULL;
|
|
hfontPreview = NULL;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL PreviewFile(HWND hwnd, LPSTR szFile)
|
|
{
|
|
if (hwndPreview != hwnd)
|
|
return FALSE;
|
|
|
|
achPreview[0] = 0;
|
|
|
|
if (hdibPreview)
|
|
GlobalFree(hdibPreview);
|
|
|
|
hdibPreview = NULL;
|
|
|
|
if (szFile)
|
|
{
|
|
hdibPreview = GetRiffDisp(szFile, achPreview, NUMELMS(achPreview));
|
|
}
|
|
|
|
PreviewPaint(hwnd);
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL PreviewPaint(HWND hwnd)
|
|
{
|
|
RECT rc;
|
|
RECT rcPreview;
|
|
RECT rcImage;
|
|
RECT rcText;
|
|
HDC hdc;
|
|
HBRUSH hbr;
|
|
int dx;
|
|
int dy;
|
|
LPBITMAPINFOHEADER lpbi;
|
|
|
|
if (hwndPreview != hwnd)
|
|
return FALSE;
|
|
|
|
//
|
|
// locate the preview in the lower corner of the dialog (below the
|
|
// cancel button)
|
|
//
|
|
//////!!! find a better way to do this.
|
|
GetClientRect(hwnd, &rcPreview);
|
|
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
|
|
ScreenToClient(hwnd, (LPPOINT)&rc);
|
|
ScreenToClient(hwnd, (LPPOINT)&rc+1);
|
|
|
|
rcPreview.top = rc.bottom + (rc.bottom - rc.top) + 12;
|
|
rcPreview.left = rc.left;
|
|
rcPreview.right = rc.right;
|
|
rcPreview.bottom -= 4; // leave a little room at the bottom
|
|
//////
|
|
|
|
hdc = GetDC(hwnd);
|
|
hbr = (HBRUSH)DefWindowProc(hwnd, WM_CTLCOLOR, (WPARAM)hdc, MAKELONG(hwnd, CTLCOLOR_DLG));
|
|
SelectObject(hdc, hfontPreview);
|
|
SetStretchBltMode(hdc, COLORONCOLOR);
|
|
|
|
InflateRect(&rcPreview, 4, 1);
|
|
FillRect(hdc, &rcPreview, hbr);
|
|
IntersectClipRect(hdc, rcPreview.left, rcPreview.top, rcPreview.right, rcPreview.bottom);
|
|
InflateRect(&rcPreview, -4, -1);
|
|
|
|
//
|
|
// compute the text rect, using DrawText
|
|
//
|
|
rcText = rcPreview;
|
|
rcText.bottom = rcText.top;
|
|
|
|
DrawText(hdc, achPreview, -1, &rcText, DT_CALCRECT|DT_LEFT|DT_WORDBREAK);
|
|
|
|
//
|
|
// compute the image size
|
|
//
|
|
if (hdibPreview && hdd)
|
|
{
|
|
lpbi = (LPVOID)GlobalLock(hdibPreview);
|
|
|
|
#if 0
|
|
//
|
|
// DISP(CF_DIB) chunks are messed up they contain a DIB file! not
|
|
// a CF_DIB, skip over the header if it is there.
|
|
//
|
|
if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
|
|
(LPSTR)lpbi += sizeof(BITMAPFILEHEADER);
|
|
#endif
|
|
|
|
rcImage = rcPreview;
|
|
|
|
//
|
|
// if wider than preview area scale to fit
|
|
//
|
|
if ((int)lpbi->biWidth > rcImage.right - rcImage.left)
|
|
{
|
|
rcImage.bottom = rcImage.top + MulDiv((int)lpbi->biHeight,rcImage.right-rcImage.left,(int)lpbi->biWidth);
|
|
}
|
|
//
|
|
// if x2 will fit then use it
|
|
//
|
|
else if ((int)lpbi->biWidth * 2 < rcImage.right - rcImage.left)
|
|
{
|
|
rcImage.right = rcImage.left + (int)lpbi->biWidth*2;
|
|
rcImage.bottom = rcImage.top + (int)lpbi->biHeight*2;
|
|
}
|
|
//
|
|
// else center the image in the preview area
|
|
//
|
|
else
|
|
{
|
|
rcImage.right = rcImage.left + (int)lpbi->biWidth;
|
|
rcImage.bottom = rcImage.top + (int)lpbi->biHeight;
|
|
}
|
|
|
|
if (rcImage.bottom > rcPreview.bottom - (rcText.bottom - rcText.top))
|
|
{
|
|
rcImage.bottom = rcPreview.bottom - (rcText.bottom - rcText.top);
|
|
|
|
rcImage.right = rcPreview.left + MulDiv((int)lpbi->biWidth,rcImage.bottom-rcImage.top,(int)lpbi->biHeight);
|
|
rcImage.left = rcPreview.left;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetRectEmpty(&rcImage);
|
|
}
|
|
|
|
//
|
|
// now center
|
|
//
|
|
dx = ((rcPreview.right - rcPreview.left) - (rcText.right - rcText.left))/2;
|
|
OffsetRect(&rcText, dx, 0);
|
|
|
|
dx = ((rcPreview.right - rcPreview.left) - (rcImage.right - rcImage.left))/2;
|
|
OffsetRect(&rcImage, dx, 0);
|
|
|
|
dy = rcPreview.bottom - rcPreview.top;
|
|
dy -= rcImage.bottom - rcImage.top;
|
|
dy -= rcText.bottom - rcText.top;
|
|
|
|
if (dy < 0)
|
|
dy = 0;
|
|
else
|
|
dy = dy / 2;
|
|
|
|
OffsetRect(&rcImage, 0, dy);
|
|
OffsetRect(&rcText, 0, dy + rcImage.bottom - rcImage.top + 2);
|
|
|
|
//
|
|
// now draw
|
|
//
|
|
DrawText(hdc, achPreview, -1, &rcText, DT_LEFT|DT_WORDBREAK);
|
|
|
|
if (hdibPreview && hdd)
|
|
{
|
|
DrawDibDraw(hdd,
|
|
hdc,
|
|
rcImage.left,
|
|
rcImage.top,
|
|
rcImage.right - rcImage.left,
|
|
rcImage.bottom - rcImage.top,
|
|
lpbi,
|
|
NULL,
|
|
0,
|
|
0,
|
|
-1,
|
|
-1,
|
|
0);
|
|
|
|
InflateRect(&rcImage, 1, 1);
|
|
FrameRect(hdc, &rcImage, GetStockObject(BLACK_BRUSH));
|
|
}
|
|
|
|
ReleaseDC(hwnd, hdc);
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
****************************************************************************/
|
|
|
|
static UINT (CALLBACK *lpfnOldHook)(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
/* Combo boxes */
|
|
#define cmb1 0x0470
|
|
#define cmb2 0x0471
|
|
/* Listboxes */
|
|
#define lst1 0x0460
|
|
#define lst2 0x0461
|
|
/* Edit controls */
|
|
#define edt1 0x0480
|
|
|
|
#define ID_TIMER 1234
|
|
#define PREVIEWWAIT 1000
|
|
|
|
WORD FAR PASCAL _export GetFileNamePreviewHook(HWND hwnd, unsigned msg, WORD wParam, LONG lParam)
|
|
{
|
|
int i;
|
|
char ach[80];
|
|
|
|
switch (msg) {
|
|
case WM_COMMAND:
|
|
switch (wParam)
|
|
{
|
|
case lst1:
|
|
if (HIWORD(lParam) == LBN_SELCHANGE)
|
|
{
|
|
KillTimer(hwnd, ID_TIMER);
|
|
SetTimer(hwnd, ID_TIMER, PREVIEWWAIT, NULL);
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
KillTimer(hwnd, ID_TIMER);
|
|
PreviewFile(hwnd, NULL);
|
|
break;
|
|
|
|
case cmb1:
|
|
case cmb2:
|
|
case lst2:
|
|
if (HIWORD(lParam) == LBN_SELCHANGE)
|
|
{
|
|
KillTimer(hwnd, ID_TIMER);
|
|
PreviewFile(hwnd, NULL);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
if (wParam == ID_TIMER)
|
|
{
|
|
KillTimer(hwnd, ID_TIMER);
|
|
|
|
ach[0] = 0;
|
|
i = (int)SendDlgItemMessage(hwnd, lst1, LB_GETCURSEL, 0, 0L);
|
|
SendDlgItemMessage(hwnd, lst1, LB_GETTEXT, i, (LONG)(LPSTR)ach);
|
|
PreviewFile(hwnd, ach);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_QUERYNEWPALETTE:
|
|
case WM_PALETTECHANGED:
|
|
case WM_PAINT:
|
|
PreviewPaint(hwnd);
|
|
break;
|
|
|
|
case WM_INITDIALOG:
|
|
PreviewOpen(hwnd);
|
|
|
|
if (!lpfnOldHook)
|
|
return TRUE;
|
|
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
PreviewClose(hwnd);
|
|
break;
|
|
}
|
|
|
|
if (lpfnOldHook)
|
|
return (*lpfnOldHook)(hwnd, msg, wParam, lParam);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* @doc EXTERNAL GetOpenFileNamePreview
|
|
*
|
|
* @api BOOL | GetOpenFileNamePreview | This function is similar
|
|
* to <f GetOpenFileName> defined in COMMDLG.DLL except that
|
|
* it has a preview window to display the movie about to be opened.
|
|
*
|
|
* @parm LPOPENFILENAME | lpofn | Points to an <t OPENFILENAME> structure
|
|
* used to initialize the dialog box. On return, the structure
|
|
* contains information about the user's file selection.
|
|
*
|
|
* @rdesc Returns true if a file was opened.
|
|
*
|
|
* @comm For more information on this function, see the description for
|
|
* <f GetOpenFileName>.
|
|
*
|
|
* @xref <f GetOpenFileName>
|
|
*
|
|
*************************************************************************/
|
|
BOOL FAR PASCAL GetOpenFileNamePreview(LPOPENFILENAME lpofn)
|
|
{
|
|
BOOL fHook;
|
|
BOOL f;
|
|
|
|
if (hwndPreview)
|
|
return GetOpenFileName(lpofn);
|
|
|
|
fHook = (BOOL)(lpofn->Flags & OFN_ENABLEHOOK);
|
|
|
|
if (fHook)
|
|
lpfnOldHook = lpofn->lpfnHook;
|
|
|
|
(FARPROC)lpofn->lpfnHook = MakeProcInstance((FARPROC)GetFileNamePreviewHook, GetHInstance());
|
|
lpofn->Flags |= OFN_ENABLEHOOK;
|
|
|
|
f = GetOpenFileName(lpofn);
|
|
|
|
FreeProcInstance((FARPROC)lpofn->lpfnHook);
|
|
|
|
if (fHook)
|
|
lpofn->lpfnHook = lpfnOldHook;
|
|
else
|
|
lpofn->Flags &= ~OFN_ENABLEHOOK;
|
|
|
|
return f;
|
|
}
|
|
|
|
HANDLE AVIFirstFrame(LPSTR szFile)
|
|
{
|
|
HANDLE h = NULL;
|
|
LPBITMAPINFOHEADER lpbi;
|
|
DWORD dwSize;
|
|
PAVISTREAM pavi;
|
|
PGETFRAME pg;
|
|
|
|
if (AVIStreamOpenFromFile(&pavi, szFile, streamtypeVIDEO, 0, OF_READ, NULL) == AVIERR_OK)
|
|
{
|
|
pg = AVIStreamGetFrameOpen(pavi, NULL);
|
|
if (pg) {
|
|
lpbi = AVIStreamGetFrame(pg, 0);
|
|
|
|
if (lpbi)
|
|
{
|
|
dwSize = lpbi->biSize + lpbi->biSizeImage + lpbi->biClrUsed * sizeof(RGBQUAD);
|
|
h = GlobalAlloc(GHND, dwSize);
|
|
|
|
if (h)
|
|
hmemcpy(GlobalLock(h), lpbi, dwSize);
|
|
}
|
|
|
|
AVIStreamGetFrameClose(pg);
|
|
}
|
|
AVIStreamClose(pavi);
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* get both the DISP(CF_DIB) and the DISP(CF_TEXT) info in one pass, this is
|
|
* much faster than doing multiple passes over the file.
|
|
*
|
|
****************************************************************************/
|
|
|
|
HANDLE GetRiffDisp(LPSTR lpszFile, LPSTR szText, int iLen)
|
|
{
|
|
HMMIO hmmio;
|
|
MMCKINFO ck;
|
|
MMCKINFO ckINFO;
|
|
MMCKINFO ckRIFF;
|
|
HANDLE h = NULL;
|
|
LONG lSize;
|
|
DWORD dw;
|
|
HCURSOR hcur = NULL;
|
|
|
|
if (szText)
|
|
szText[0] = 0;
|
|
|
|
/* Open the file */
|
|
hmmio = mmioOpen(lpszFile, NULL, MMIO_ALLOCBUF | MMIO_READ);
|
|
|
|
if (hmmio == NULL)
|
|
return NULL;
|
|
|
|
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;
|
|
|
|
while (!mmioDescend(hmmio, &ck, &ckRIFF, 0))
|
|
{
|
|
if (ck.ckid == FOURCC_DISP)
|
|
{
|
|
if (hcur == NULL)
|
|
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
/* Read dword into dw, break if read unsuccessful */
|
|
if (mmioRead(hmmio, (LPVOID)&dw, sizeof(dw)) != 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;
|
|
}
|
|
else if ((int)dw == CF_TEXT && szText[0] == 0)
|
|
{
|
|
if (lSize > iLen-1)
|
|
lSize = iLen-1;
|
|
|
|
szText[lSize] = 0;
|
|
|
|
if (mmioRead(hmmio, szText, lSize) != lSize)
|
|
goto error;
|
|
}
|
|
}
|
|
else if (ck.ckid == FOURCC_LIST &&
|
|
ck.fccType == FOURCC_INFO &&
|
|
szText[0] == 0)
|
|
{
|
|
while (!mmioDescend(hmmio, &ckINFO, &ck, 0))
|
|
{
|
|
switch (ckINFO.ckid)
|
|
{
|
|
case FOURCC_INAM:
|
|
// case FOURCC_ISBJ:
|
|
|
|
lSize = ck.cksize;
|
|
|
|
if (lSize > iLen-1)
|
|
lSize = iLen-1;
|
|
|
|
szText[lSize] = 0;
|
|
|
|
if (mmioRead(hmmio, szText, lSize) != lSize)
|
|
goto error;
|
|
|
|
break;
|
|
}
|
|
|
|
if (mmioAscend(hmmio, &ckINFO, 0))
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if we have both a picture and a title, then exit.
|
|
//
|
|
if (h != NULL && szText[0] != 0)
|
|
break;
|
|
|
|
/* Ascend so that we can descend into next chunk
|
|
*/
|
|
if (mmioAscend(hmmio, &ck, 0))
|
|
break;
|
|
}
|
|
|
|
goto exit;
|
|
|
|
error:
|
|
if (h)
|
|
GlobalFree(h);
|
|
|
|
h = NULL;
|
|
ckRIFF.fccType = 0;
|
|
|
|
exit:
|
|
mmioClose(hmmio, 0);
|
|
|
|
//
|
|
// !!!we need a way to preview other file types!
|
|
// !!!what about text.
|
|
//
|
|
if (h == NULL && ckRIFF.fccType == FOURCC_AVI)
|
|
{
|
|
if (hcur == NULL)
|
|
hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
h = AVIFirstFrame(lpszFile);
|
|
}
|
|
|
|
//
|
|
// verify and correct the DIB
|
|
//
|
|
if (h)
|
|
{
|
|
LPBITMAPINFOHEADER lpbi;
|
|
|
|
lpbi = (LPVOID)GlobalLock(h);
|
|
|
|
if (lpbi->biSize < sizeof(BITMAPINFOHEADER))
|
|
goto error;
|
|
|
|
if (lpbi->biClrUsed == 0)
|
|
lpbi->biClrUsed = DibNumColors(lpbi);
|
|
|
|
if (lpbi->biSizeImage == 0)
|
|
lpbi->biSizeImage = DibSizeImage(lpbi);
|
|
|
|
if (DibSize(lpbi) > GlobalSize(h))
|
|
goto error;
|
|
}
|
|
|
|
if (hcur)
|
|
SetCursor(hcur);
|
|
|
|
return h;
|
|
}
|