Source code of Windows XP (NT5)
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.

609 lines
16 KiB

  1. /****************************************************************************
  2. *
  3. * MODULE : RIFFDISP.C
  4. *
  5. ****************************************************************************/
  6. #include <win32.h>
  7. #include <mmsystem.h>
  8. #include <commdlg.h>
  9. #include <vfw.h>
  10. #include "riffdisp.h"
  11. static HWND hwndPreview;
  12. static HANDLE hdibPreview;
  13. static char achPreview[MAX_PATH];
  14. static HFONT hfontPreview;
  15. static HDRAWDIB hdd;
  16. #define GetHInstance() (HINSTANCE)(SELECTOROF((LPVOID)&hwndPreview))
  17. #define DibSizeImage(lpbi) (\
  18. (DWORD)(UINT)((((int)lpbi->biBitCount*(int)lpbi->biWidth+31)&~31)>>3) * \
  19. (DWORD)(UINT)lpbi->biHeight)
  20. #define DibSize(lpbi) \
  21. (lpbi->biSize + ((int)lpbi->biClrUsed * sizeof(RGBQUAD)) + lpbi->biSizeImage)
  22. #define DibNumColors(lpbi) \
  23. (lpbi->biBitCount <= 8 ? (1 << (int)lpbi->biBitCount) : 0)
  24. /***************************************************************************
  25. *
  26. ****************************************************************************/
  27. //#define FOURCC_RIFF mmioFOURCC('R','I','F','F')
  28. #define FOURCC_AVI mmioFOURCC('A','V','I',' ')
  29. #define FOURCC_INFO mmioFOURCC('I','N','F','O')
  30. #define FOURCC_DISP mmioFOURCC('D','I','S','P')
  31. #define FOURCC_INAM mmioFOURCC('I','N','A','M')
  32. #define FOURCC_ISBJ mmioFOURCC('I','S','B','J')
  33. BOOL PreviewOpen(HWND hwnd);
  34. BOOL PreviewFile(HWND hwnd, LPSTR szFile);
  35. BOOL PreviewPaint(HWND hwnd);
  36. BOOL PreviewClose(HWND hwnd);
  37. HANDLE ReadDisp(LPSTR lpszFile, int cf, LPSTR pv, int iLen);
  38. HANDLE ReadInfo(LPSTR lpszFile, FOURCC fcc, LPSTR pv, int iLen);
  39. HANDLE GetRiffDisp(LPSTR lpszFile, LPSTR szText, int iLen);
  40. /***************************************************************************
  41. *
  42. ****************************************************************************/
  43. BOOL PreviewOpen(HWND hwnd)
  44. {
  45. LOGFONT lf;
  46. if (hwndPreview)
  47. return FALSE;
  48. hwndPreview = hwnd;
  49. hdd = DrawDibOpen();
  50. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (LPVOID)&lf, 0);
  51. hfontPreview = CreateFontIndirect(&lf);
  52. }
  53. /***************************************************************************
  54. *
  55. ****************************************************************************/
  56. BOOL PreviewClose(HWND hwnd)
  57. {
  58. if (hwndPreview != hwnd)
  59. return FALSE;
  60. if (hdibPreview)
  61. GlobalFree(hdibPreview);
  62. if (hfontPreview)
  63. DeleteObject(hfontPreview);
  64. if (hdd)
  65. DrawDibClose(hdd);
  66. achPreview[0] = 0;
  67. hdd = NULL;
  68. hwndPreview = NULL;
  69. hdibPreview = NULL;
  70. hfontPreview = NULL;
  71. }
  72. /***************************************************************************
  73. *
  74. ****************************************************************************/
  75. BOOL PreviewFile(HWND hwnd, LPSTR szFile)
  76. {
  77. if (hwndPreview != hwnd)
  78. return FALSE;
  79. achPreview[0] = 0;
  80. if (hdibPreview)
  81. GlobalFree(hdibPreview);
  82. hdibPreview = NULL;
  83. if (szFile)
  84. {
  85. hdibPreview = GetRiffDisp(szFile, achPreview, NUMELMS(achPreview));
  86. }
  87. PreviewPaint(hwnd);
  88. return TRUE;
  89. }
  90. /***************************************************************************
  91. *
  92. ****************************************************************************/
  93. BOOL PreviewPaint(HWND hwnd)
  94. {
  95. RECT rc;
  96. RECT rcPreview;
  97. RECT rcImage;
  98. RECT rcText;
  99. HDC hdc;
  100. HBRUSH hbr;
  101. int dx;
  102. int dy;
  103. LPBITMAPINFOHEADER lpbi;
  104. if (hwndPreview != hwnd)
  105. return FALSE;
  106. //
  107. // locate the preview in the lower corner of the dialog (below the
  108. // cancel button)
  109. //
  110. //////!!! find a better way to do this.
  111. GetClientRect(hwnd, &rcPreview);
  112. GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rc);
  113. ScreenToClient(hwnd, (LPPOINT)&rc);
  114. ScreenToClient(hwnd, (LPPOINT)&rc+1);
  115. rcPreview.top = rc.bottom + (rc.bottom - rc.top) + 12;
  116. rcPreview.left = rc.left;
  117. rcPreview.right = rc.right;
  118. rcPreview.bottom -= 4; // leave a little room at the bottom
  119. //////
  120. hdc = GetDC(hwnd);
  121. hbr = (HBRUSH)DefWindowProc(hwnd, WM_CTLCOLOR, (WPARAM)hdc, MAKELONG(hwnd, CTLCOLOR_DLG));
  122. SelectObject(hdc, hfontPreview);
  123. SetStretchBltMode(hdc, COLORONCOLOR);
  124. InflateRect(&rcPreview, 4, 1);
  125. FillRect(hdc, &rcPreview, hbr);
  126. IntersectClipRect(hdc, rcPreview.left, rcPreview.top, rcPreview.right, rcPreview.bottom);
  127. InflateRect(&rcPreview, -4, -1);
  128. //
  129. // compute the text rect, using DrawText
  130. //
  131. rcText = rcPreview;
  132. rcText.bottom = rcText.top;
  133. DrawText(hdc, achPreview, -1, &rcText, DT_CALCRECT|DT_LEFT|DT_WORDBREAK);
  134. //
  135. // compute the image size
  136. //
  137. if (hdibPreview && hdd)
  138. {
  139. lpbi = (LPVOID)GlobalLock(hdibPreview);
  140. #if 0
  141. //
  142. // DISP(CF_DIB) chunks are messed up they contain a DIB file! not
  143. // a CF_DIB, skip over the header if it is there.
  144. //
  145. if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
  146. (LPSTR)lpbi += sizeof(BITMAPFILEHEADER);
  147. #endif
  148. rcImage = rcPreview;
  149. //
  150. // if wider than preview area scale to fit
  151. //
  152. if ((int)lpbi->biWidth > rcImage.right - rcImage.left)
  153. {
  154. rcImage.bottom = rcImage.top + MulDiv((int)lpbi->biHeight,rcImage.right-rcImage.left,(int)lpbi->biWidth);
  155. }
  156. //
  157. // if x2 will fit then use it
  158. //
  159. else if ((int)lpbi->biWidth * 2 < rcImage.right - rcImage.left)
  160. {
  161. rcImage.right = rcImage.left + (int)lpbi->biWidth*2;
  162. rcImage.bottom = rcImage.top + (int)lpbi->biHeight*2;
  163. }
  164. //
  165. // else center the image in the preview area
  166. //
  167. else
  168. {
  169. rcImage.right = rcImage.left + (int)lpbi->biWidth;
  170. rcImage.bottom = rcImage.top + (int)lpbi->biHeight;
  171. }
  172. if (rcImage.bottom > rcPreview.bottom - (rcText.bottom - rcText.top))
  173. {
  174. rcImage.bottom = rcPreview.bottom - (rcText.bottom - rcText.top);
  175. rcImage.right = rcPreview.left + MulDiv((int)lpbi->biWidth,rcImage.bottom-rcImage.top,(int)lpbi->biHeight);
  176. rcImage.left = rcPreview.left;
  177. }
  178. }
  179. else
  180. {
  181. SetRectEmpty(&rcImage);
  182. }
  183. //
  184. // now center
  185. //
  186. dx = ((rcPreview.right - rcPreview.left) - (rcText.right - rcText.left))/2;
  187. OffsetRect(&rcText, dx, 0);
  188. dx = ((rcPreview.right - rcPreview.left) - (rcImage.right - rcImage.left))/2;
  189. OffsetRect(&rcImage, dx, 0);
  190. dy = rcPreview.bottom - rcPreview.top;
  191. dy -= rcImage.bottom - rcImage.top;
  192. dy -= rcText.bottom - rcText.top;
  193. if (dy < 0)
  194. dy = 0;
  195. else
  196. dy = dy / 2;
  197. OffsetRect(&rcImage, 0, dy);
  198. OffsetRect(&rcText, 0, dy + rcImage.bottom - rcImage.top + 2);
  199. //
  200. // now draw
  201. //
  202. DrawText(hdc, achPreview, -1, &rcText, DT_LEFT|DT_WORDBREAK);
  203. if (hdibPreview && hdd)
  204. {
  205. DrawDibDraw(hdd,
  206. hdc,
  207. rcImage.left,
  208. rcImage.top,
  209. rcImage.right - rcImage.left,
  210. rcImage.bottom - rcImage.top,
  211. lpbi,
  212. NULL,
  213. 0,
  214. 0,
  215. -1,
  216. -1,
  217. 0);
  218. InflateRect(&rcImage, 1, 1);
  219. FrameRect(hdc, &rcImage, GetStockObject(BLACK_BRUSH));
  220. }
  221. ReleaseDC(hwnd, hdc);
  222. return TRUE;
  223. }
  224. /***************************************************************************
  225. *
  226. ****************************************************************************/
  227. static UINT (CALLBACK *lpfnOldHook)(HWND, UINT, WPARAM, LPARAM);
  228. /* Combo boxes */
  229. #define cmb1 0x0470
  230. #define cmb2 0x0471
  231. /* Listboxes */
  232. #define lst1 0x0460
  233. #define lst2 0x0461
  234. /* Edit controls */
  235. #define edt1 0x0480
  236. #define ID_TIMER 1234
  237. #define PREVIEWWAIT 1000
  238. WORD FAR PASCAL _export GetFileNamePreviewHook(HWND hwnd, unsigned msg, WORD wParam, LONG lParam)
  239. {
  240. int i;
  241. char ach[80];
  242. switch (msg) {
  243. case WM_COMMAND:
  244. switch (wParam)
  245. {
  246. case lst1:
  247. if (HIWORD(lParam) == LBN_SELCHANGE)
  248. {
  249. KillTimer(hwnd, ID_TIMER);
  250. SetTimer(hwnd, ID_TIMER, PREVIEWWAIT, NULL);
  251. }
  252. break;
  253. case IDOK:
  254. case IDCANCEL:
  255. KillTimer(hwnd, ID_TIMER);
  256. PreviewFile(hwnd, NULL);
  257. break;
  258. case cmb1:
  259. case cmb2:
  260. case lst2:
  261. if (HIWORD(lParam) == LBN_SELCHANGE)
  262. {
  263. KillTimer(hwnd, ID_TIMER);
  264. PreviewFile(hwnd, NULL);
  265. }
  266. break;
  267. }
  268. break;
  269. case WM_TIMER:
  270. if (wParam == ID_TIMER)
  271. {
  272. KillTimer(hwnd, ID_TIMER);
  273. ach[0] = 0;
  274. i = (int)SendDlgItemMessage(hwnd, lst1, LB_GETCURSEL, 0, 0L);
  275. SendDlgItemMessage(hwnd, lst1, LB_GETTEXT, i, (LONG)(LPSTR)ach);
  276. PreviewFile(hwnd, ach);
  277. return TRUE;
  278. }
  279. break;
  280. case WM_QUERYNEWPALETTE:
  281. case WM_PALETTECHANGED:
  282. case WM_PAINT:
  283. PreviewPaint(hwnd);
  284. break;
  285. case WM_INITDIALOG:
  286. PreviewOpen(hwnd);
  287. if (!lpfnOldHook)
  288. return TRUE;
  289. break;
  290. case WM_DESTROY:
  291. PreviewClose(hwnd);
  292. break;
  293. }
  294. if (lpfnOldHook)
  295. return (*lpfnOldHook)(hwnd, msg, wParam, lParam);
  296. else
  297. return FALSE;
  298. }
  299. /**************************************************************************
  300. * @doc EXTERNAL GetOpenFileNamePreview
  301. *
  302. * @api BOOL | GetOpenFileNamePreview | This function is similar
  303. * to <f GetOpenFileName> defined in COMMDLG.DLL except that
  304. * it has a preview window to display the movie about to be opened.
  305. *
  306. * @parm LPOPENFILENAME | lpofn | Points to an <t OPENFILENAME> structure
  307. * used to initialize the dialog box. On return, the structure
  308. * contains information about the user's file selection.
  309. *
  310. * @rdesc Returns true if a file was opened.
  311. *
  312. * @comm For more information on this function, see the description for
  313. * <f GetOpenFileName>.
  314. *
  315. * @xref <f GetOpenFileName>
  316. *
  317. *************************************************************************/
  318. BOOL FAR PASCAL GetOpenFileNamePreview(LPOPENFILENAME lpofn)
  319. {
  320. BOOL fHook;
  321. BOOL f;
  322. if (hwndPreview)
  323. return GetOpenFileName(lpofn);
  324. fHook = (BOOL)(lpofn->Flags & OFN_ENABLEHOOK);
  325. if (fHook)
  326. lpfnOldHook = lpofn->lpfnHook;
  327. (FARPROC)lpofn->lpfnHook = MakeProcInstance((FARPROC)GetFileNamePreviewHook, GetHInstance());
  328. lpofn->Flags |= OFN_ENABLEHOOK;
  329. f = GetOpenFileName(lpofn);
  330. FreeProcInstance((FARPROC)lpofn->lpfnHook);
  331. if (fHook)
  332. lpofn->lpfnHook = lpfnOldHook;
  333. else
  334. lpofn->Flags &= ~OFN_ENABLEHOOK;
  335. return f;
  336. }
  337. HANDLE AVIFirstFrame(LPSTR szFile)
  338. {
  339. HANDLE h = NULL;
  340. LPBITMAPINFOHEADER lpbi;
  341. DWORD dwSize;
  342. PAVISTREAM pavi;
  343. PGETFRAME pg;
  344. if (AVIStreamOpenFromFile(&pavi, szFile, streamtypeVIDEO, 0, OF_READ, NULL) == AVIERR_OK)
  345. {
  346. pg = AVIStreamGetFrameOpen(pavi, NULL);
  347. if (pg) {
  348. lpbi = AVIStreamGetFrame(pg, 0);
  349. if (lpbi)
  350. {
  351. dwSize = lpbi->biSize + lpbi->biSizeImage + lpbi->biClrUsed * sizeof(RGBQUAD);
  352. h = GlobalAlloc(GHND, dwSize);
  353. if (h)
  354. hmemcpy(GlobalLock(h), lpbi, dwSize);
  355. }
  356. AVIStreamGetFrameClose(pg);
  357. }
  358. AVIStreamClose(pavi);
  359. }
  360. return h;
  361. }
  362. /****************************************************************************
  363. *
  364. * get both the DISP(CF_DIB) and the DISP(CF_TEXT) info in one pass, this is
  365. * much faster than doing multiple passes over the file.
  366. *
  367. ****************************************************************************/
  368. HANDLE GetRiffDisp(LPSTR lpszFile, LPSTR szText, int iLen)
  369. {
  370. HMMIO hmmio;
  371. MMCKINFO ck;
  372. MMCKINFO ckINFO;
  373. MMCKINFO ckRIFF;
  374. HANDLE h = NULL;
  375. LONG lSize;
  376. DWORD dw;
  377. HCURSOR hcur = NULL;
  378. if (szText)
  379. szText[0] = 0;
  380. /* Open the file */
  381. hmmio = mmioOpen(lpszFile, NULL, MMIO_ALLOCBUF | MMIO_READ);
  382. if (hmmio == NULL)
  383. return NULL;
  384. mmioSeek(hmmio, 0, SEEK_SET);
  385. /* descend the input file into the RIFF chunk */
  386. if (mmioDescend(hmmio, &ckRIFF, NULL, 0) != 0)
  387. goto error;
  388. if (ckRIFF.ckid != FOURCC_RIFF)
  389. goto error;
  390. while (!mmioDescend(hmmio, &ck, &ckRIFF, 0))
  391. {
  392. if (ck.ckid == FOURCC_DISP)
  393. {
  394. if (hcur == NULL)
  395. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  396. /* Read dword into dw, break if read unsuccessful */
  397. if (mmioRead(hmmio, (LPVOID)&dw, sizeof(dw)) != sizeof(dw))
  398. goto error;
  399. /* Find out how much memory to allocate */
  400. lSize = ck.cksize - sizeof(dw);
  401. if ((int)dw == CF_DIB && h == NULL)
  402. {
  403. /* get a handle to memory to hold the description and lock it down */
  404. if ((h = GlobalAlloc(GHND, lSize+4)) == NULL)
  405. goto error;
  406. if (mmioRead(hmmio, GlobalLock(h), lSize) != lSize)
  407. goto error;
  408. }
  409. else if ((int)dw == CF_TEXT && szText[0] == 0)
  410. {
  411. if (lSize > iLen-1)
  412. lSize = iLen-1;
  413. szText[lSize] = 0;
  414. if (mmioRead(hmmio, szText, lSize) != lSize)
  415. goto error;
  416. }
  417. }
  418. else if (ck.ckid == FOURCC_LIST &&
  419. ck.fccType == FOURCC_INFO &&
  420. szText[0] == 0)
  421. {
  422. while (!mmioDescend(hmmio, &ckINFO, &ck, 0))
  423. {
  424. switch (ckINFO.ckid)
  425. {
  426. case FOURCC_INAM:
  427. // case FOURCC_ISBJ:
  428. lSize = ck.cksize;
  429. if (lSize > iLen-1)
  430. lSize = iLen-1;
  431. szText[lSize] = 0;
  432. if (mmioRead(hmmio, szText, lSize) != lSize)
  433. goto error;
  434. break;
  435. }
  436. if (mmioAscend(hmmio, &ckINFO, 0))
  437. break;
  438. }
  439. }
  440. //
  441. // if we have both a picture and a title, then exit.
  442. //
  443. if (h != NULL && szText[0] != 0)
  444. break;
  445. /* Ascend so that we can descend into next chunk
  446. */
  447. if (mmioAscend(hmmio, &ck, 0))
  448. break;
  449. }
  450. goto exit;
  451. error:
  452. if (h)
  453. GlobalFree(h);
  454. h = NULL;
  455. ckRIFF.fccType = 0;
  456. exit:
  457. mmioClose(hmmio, 0);
  458. //
  459. // !!!we need a way to preview other file types!
  460. // !!!what about text.
  461. //
  462. if (h == NULL && ckRIFF.fccType == FOURCC_AVI)
  463. {
  464. if (hcur == NULL)
  465. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  466. h = AVIFirstFrame(lpszFile);
  467. }
  468. //
  469. // verify and correct the DIB
  470. //
  471. if (h)
  472. {
  473. LPBITMAPINFOHEADER lpbi;
  474. lpbi = (LPVOID)GlobalLock(h);
  475. if (lpbi->biSize < sizeof(BITMAPINFOHEADER))
  476. goto error;
  477. if (lpbi->biClrUsed == 0)
  478. lpbi->biClrUsed = DibNumColors(lpbi);
  479. if (lpbi->biSizeImage == 0)
  480. lpbi->biSizeImage = DibSizeImage(lpbi);
  481. if (DibSize(lpbi) > GlobalSize(h))
  482. goto error;
  483. }
  484. if (hcur)
  485. SetCursor(hcur);
  486. return h;
  487. }