home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / video / dseqfile / dseqf.cpp next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  37.4 KB  |  1,431 lines

  1. /****************************************************************************
  2.  *
  3.  *  DSEQF.CPP
  4.  *
  5.  *  routines for reading DIB sequences
  6.  *
  7.  ***************************************************************************/
  8. /**************************************************************************
  9.  *
  10.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  11.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  13.  *  PURPOSE.
  14.  *
  15.  *  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  16.  *
  17.  **************************************************************************/
  18.  
  19. #define INC_OLE2
  20. #include <windows.h>
  21. #include <windowsx.h>
  22. #include <mmsystem.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <malloc.h>
  26. #include <ctype.h>
  27. #include <vfw.h>
  28.  
  29. #include "handler.h"
  30. #include "handler.rc"
  31.  
  32.  
  33. static DWORD NEAR PASCAL dseqParseFileName(
  34.         LPSTR lpszFileName,
  35.         LPSTR lpszTemplate,
  36.         DWORD FAR * lpdwMaxValue);
  37.  
  38. #ifdef DEBUG
  39.         static void CDECL dprintf(LPSTR, ...);
  40.         #define DPF dprintf
  41. #else
  42.         #define DPF ; / ## /
  43. #endif
  44.  
  45. ///////////////////////////////////////////////////////////////////////////
  46. ///////////////////////////////////////////////////////////////////////////
  47. ///////////////////////////////////////////////////////////////////////////
  48.  
  49. /*      -       -       -       -       -       -       -       -       */
  50.  
  51. UINT    uUseCount;
  52. BOOL    fLocked;
  53.  
  54. /*      -       -       -       -       -       -       -       -       */
  55.  
  56. //
  57. // External function called by the Class Factory to create an instance of
  58. // the DIB sequence reader/writer
  59. //
  60. HRESULT CAVIFile::Create(
  61. IUnknown FAR*   pUnknownOuter,
  62. const IID FAR&  riid,
  63. void FAR* FAR*  ppv)
  64. {
  65.         IUnknown FAR*   pUnknown;
  66.         CAVIFile FAR*   pAVIFile;
  67.         HRESULT hresult;
  68.  
  69.         pAVIFile = new FAR CAVIFile(pUnknownOuter, &pUnknown);
  70.         if (!pAVIFile)
  71.                 return ResultFromScode(E_OUTOFMEMORY);
  72.         hresult = pUnknown->QueryInterface(riid, ppv);
  73.         if (FAILED(GetScode(hresult)))
  74.                 delete pAVIFile;
  75.         return hresult;
  76. }
  77.  
  78. /*      -       -       -       -       -       -       -       -       */
  79.  
  80. //
  81. // Random C++ stuff: constructors & such...
  82. //
  83. CAVIFile::CAVIFile(
  84. IUnknown FAR*   pUnknownOuter,
  85. IUnknown FAR* FAR*      ppUnknown) :
  86.         m_Unknown(this),
  87.         m_AVIFile(this),
  88.         m_Persist(this),
  89. #ifdef CUSTOMMARSHAL
  90.         m_Marshal(this),
  91. #endif
  92.         m_AVIStream(this)
  93. {
  94.         if (pUnknownOuter)
  95.                 m_pUnknownOuter = pUnknownOuter;
  96.         else
  97.                 m_pUnknownOuter = &m_Unknown;
  98.         *ppUnknown = &m_Unknown;
  99. }
  100.  
  101. /*      -       -       -       -       -       -       -       -       */
  102.  
  103. CAVIFile::CUnknownImpl::CUnknownImpl(
  104. CAVIFile FAR*   pAVIFile)
  105. {
  106.         m_pAVIFile = pAVIFile;
  107.         m_refs = 0;
  108. }
  109.  
  110. /*      -       -       -       -       -       -       -       -       */
  111.  
  112. //
  113. // This QueryInterface function allows a caller to move between the various
  114. // interfaces the object presents
  115. //
  116. STDMETHODIMP CAVIFile::CUnknownImpl::QueryInterface(
  117. const IID FAR&  iid,
  118. void FAR* FAR*  ppv)
  119. {
  120.         if (iid == IID_IUnknown)
  121.                 *ppv = &m_pAVIFile->m_Unknown;
  122.         else if (iid == IID_IAVIFile)
  123.                 *ppv = &m_pAVIFile->m_AVIFile;
  124.         else if (iid == IID_IAVIStream)
  125.                 *ppv = &m_pAVIFile->m_AVIStream;
  126.         else if (iid == IID_IPersistFile)
  127.                 *ppv = &m_pAVIFile->m_Persist;
  128. #ifdef CUSTOMMARSHAL
  129.         else if (iid == IID_IMarshal)
  130.                 *ppv = &m_pAVIFile->m_Marshal;
  131. #endif
  132.         else
  133.                 return ResultFromScode(E_NOINTERFACE);
  134.         AddRef();
  135.         return NULL;
  136. }
  137.  
  138. /*      -       -       -       -       -       -       -       -       */
  139.  
  140. STDMETHODIMP_(ULONG) CAVIFile::CUnknownImpl::AddRef()
  141. {
  142.         uUseCount++;
  143.         return ++m_refs;
  144. }
  145.  
  146. /*      -       -       -       -       -       -       -       -       */
  147.  
  148. //
  149. // All calls to AddRef, Release, QueryInterface for the file or stream
  150. // functions are redirected to the Unknown implementation...
  151. //
  152. CAVIFile::CAVIFileImpl::CAVIFileImpl(
  153. CAVIFile FAR*   pAVIFile)
  154. {
  155.         m_pAVIFile = pAVIFile;
  156. }
  157.  
  158. /*      -       -       -       -       -       -       -       -       */
  159.  
  160. CAVIFile::CAVIFileImpl::~CAVIFileImpl()
  161. {
  162. }
  163.  
  164. /*      -       -       -       -       -       -       -       -       */
  165.  
  166. STDMETHODIMP CAVIFile::CAVIFileImpl::QueryInterface(
  167. const IID FAR&  iid,
  168. void FAR* FAR*  ppv)
  169. {
  170.         return m_pAVIFile->m_pUnknownOuter->QueryInterface(iid, ppv);
  171. }
  172.  
  173. /*      -       -       -       -       -       -       -       -       */
  174.  
  175. STDMETHODIMP_(ULONG) CAVIFile::CAVIFileImpl::AddRef()
  176. {
  177.         return m_pAVIFile->m_pUnknownOuter->AddRef();
  178. }
  179.  
  180. /*      -       -       -       -       -       -       -       -       */
  181.  
  182. STDMETHODIMP_(ULONG) CAVIFile::CAVIFileImpl::Release()
  183. {
  184.         return m_pAVIFile->m_pUnknownOuter->Release();
  185. }
  186.  
  187. /*      -       -       -       -       -       -       -       -       */
  188.  
  189. CAVIFile::CAVIStreamImpl::CAVIStreamImpl(
  190. CAVIFile FAR*   pAVIFile)
  191. {
  192.         m_pAVIFile = pAVIFile;
  193. }
  194.  
  195. /*      -       -       -       -       -       -       -       -       */
  196.  
  197. CAVIFile::CAVIStreamImpl::~CAVIStreamImpl()
  198. {
  199. }
  200.  
  201. /*      -       -       -       -       -       -       -       -       */
  202.  
  203. STDMETHODIMP CAVIFile::CAVIStreamImpl::QueryInterface(
  204. const IID FAR&  iid,
  205. void FAR* FAR*  ppv)
  206. {
  207.         return m_pAVIFile->m_pUnknownOuter->QueryInterface(iid, ppv);
  208. }
  209.  
  210. /*      -       -       -       -       -       -       -       -       */
  211.  
  212. STDMETHODIMP_(ULONG) CAVIFile::CAVIStreamImpl::AddRef()
  213. {
  214.         return m_pAVIFile->m_pUnknownOuter->AddRef();
  215. }
  216.  
  217. /*      -       -       -       -       -       -       -       -       */
  218.  
  219. STDMETHODIMP_(ULONG) CAVIFile::CAVIStreamImpl::Release()
  220. {
  221.         return m_pAVIFile->m_pUnknownOuter->Release();
  222. }
  223.  
  224.  
  225. // --- IPersistFile implementation --------------------------------------
  226.  
  227. CAVIFile::CPersistFileImpl::CPersistFileImpl(CAVIFile FAR* pAVIFile)
  228. {
  229.     m_pAVIFile = pAVIFile;
  230. }
  231.  
  232. STDMETHODIMP
  233. CAVIFile::CPersistFileImpl::QueryInterface(REFIID riid, LPVOID FAR* ppv)
  234. {
  235.         return m_pAVIFile->m_pUnknownOuter->QueryInterface(riid, ppv);
  236. }
  237.  
  238. STDMETHODIMP_(ULONG)
  239. CAVIFile::CPersistFileImpl::AddRef()
  240. {
  241.         return m_pAVIFile->m_pUnknownOuter->AddRef();
  242. }
  243.  
  244. STDMETHODIMP_(ULONG)
  245. CAVIFile::CPersistFileImpl::Release()
  246. {
  247.         return m_pAVIFile->m_pUnknownOuter->Release();
  248. }
  249.  
  250. // *** IPersist methods ***
  251. STDMETHODIMP
  252. CAVIFile::CPersistFileImpl::GetClassID (LPCLSID lpClassID)
  253. {
  254.         *lpClassID = CLSID_DIBSEQFileReader;
  255.  
  256.         return NOERROR;
  257. }
  258.  
  259. // *** IPersistFile methods ***
  260. STDMETHODIMP
  261. CAVIFile::CPersistFileImpl::IsDirty ()
  262. {
  263.     if (m_pAVIFile->fDirty) {
  264.         return NOERROR;
  265.     } else {
  266.         return ResultFromScode(S_FALSE);
  267.     }
  268. }
  269.  
  270. /*      -       -       -       -       -       -       -       -       */
  271.  
  272. //
  273. // This function takes the name of the first file in a DIB sequence, and
  274. // returns a printf() specifier which can be used to create the names in
  275. // the sequence, along with minimum and maximum values that can be used.
  276. //
  277. //
  278. // Examples:
  279. //  lpszFileName = "FOO0047.DIB"
  280. //       -> lpszTemplate = "FOO%04d.DIB", dwMaxValue = 9999, return = 47
  281. //
  282. //  lpszFileName = "TEST01.DIB"
  283. //       -> lpszTemplate = "TEST%01d.DIB", dwMaxValue = 9, return = 1
  284. //
  285. //  lpszFileName = "TEST1.DIB"
  286. //       -> lpszTemplate = "TEST%d.DIB", dwMaxValue = 9999, return = 1
  287. //
  288. //  lpszFileName = "SINGLE.DIB"
  289. //       -> lpszTemplate = "SINGLE.DIB", dwMaxValue = 0, return = 0
  290. //
  291. static DWORD NEAR PASCAL dseqParseFileName(
  292. LPSTR lpszFileName,
  293. LPSTR lpszTemplate,
  294. DWORD FAR * lpdwMaxValue)
  295. {
  296.         char    achTemp[_MAX_PATH];
  297.         DWORD   dwFirst;
  298.         WORD    wFieldWidth;
  299.         DWORD   dwMult;
  300.         BOOL    fLeadingZero = FALSE;
  301.  
  302.         LPSTR   lp;
  303.         LPSTR   lp2;
  304.         LPSTR   lpExt;
  305.  
  306.         /* Find end of string */
  307.         lp2 = lpszFileName;
  308.         lp = achTemp;
  309.         while (*lp2)
  310.         *lp++ = *lp2++;
  311.  
  312.         *lp = '\0';
  313.  
  314.         /* Make lp2 point at last character of base filename (w/o extension) */
  315.         /* Make lpExt point at the extension (without the dot) */
  316.         for (lp2 = lp; *lp2 != '.'; lp2--)
  317.         {
  318.                 lpExt = lp2;
  319.                 if ((lp2 == achTemp) || (*lp2 == '\\')
  320.                         || (*lp2 == ':') || (*lp2 == '!'))
  321.                 {
  322.                         /* There is no extension */
  323.                         lp2 = lp;
  324.                         lpExt = lp;
  325.                         break;
  326.                 }
  327.         }
  328.  
  329.         lp2--;
  330.  
  331.         // Count the number of numeric characters here....
  332.         dwFirst = 0;
  333.         wFieldWidth = 0;
  334.         dwMult = 1;
  335.         while (lp2 >= achTemp && (*lp2 >= '0') && (*lp2 <= '9')) {
  336.         fLeadingZero = (*lp2 == '0');
  337.         dwFirst += dwMult * (*(lp2--) - '0');
  338.         dwMult *= 10;
  339.         wFieldWidth++;
  340.         }
  341.  
  342.         *lpdwMaxValue = dwMult - 1;
  343.  
  344.         lp2++;
  345.         *lp2 = '\0';
  346.  
  347.         // Make the format specifier....
  348.         if (wFieldWidth) {
  349.         if (fLeadingZero) {
  350.                 wsprintf((LPSTR) lpszTemplate,"%s%%0%ulu.%s",
  351.                         (LPSTR) achTemp, wFieldWidth,(LPSTR) lpExt);
  352.         } else {
  353.                 wsprintf((LPSTR) lpszTemplate,"%s%%lu.%s",
  354.                         (LPSTR) achTemp, (LPSTR) lpExt);
  355.                 *lpdwMaxValue = 999999L;
  356.                 // !!! This should really be based on the number of
  357.                 // characters left after the base name....
  358.         }
  359.         } else
  360.         wsprintf((LPSTR) lpszTemplate,"%s.%s",
  361.                         (LPSTR) achTemp, (LPSTR) lpExt);
  362.         DPF("First = %lu, Width = %u, Template = '%s'\n",dwFirst, wFieldWidth, lpszTemplate);
  363.  
  364.         return dwFirst;
  365. }
  366.  
  367. /*      -       -       -       -       -       -       -       -       */
  368.  
  369. #define SLASH(c) ((c) == '/' || (c) == '\\')
  370.  
  371. /*--------------------------------------------------------------+
  372. | FileName  - return a pointer to the filename part of szPath   |
  373. |             with no preceding path.                           |
  374. +--------------------------------------------------------------*/
  375. LPSTR FAR FileName(
  376. LPCSTR lszPath)
  377. {
  378.         LPCSTR  lszCur;
  379.  
  380.         for (lszCur = lszPath + lstrlen(lszPath); lszCur > lszPath && !SLASH(*lszCur) && *lszCur != ':';)
  381.                 lszCur = AnsiPrev(lszPath, lszCur);
  382.         if (lszCur == lszPath)
  383.                 return (LPSTR)lszCur;
  384.         else
  385.                 return (LPSTR)(lszCur + 1);
  386. }
  387.  
  388. /*      -       -       -       -       -       -       -       -       */
  389.  
  390. //
  391. // "Open" a DIB sequence, by parsing the filename and counting the number
  392. // of frames actually present....
  393. //
  394. STDMETHODIMP
  395. CAVIFile::CPersistFileImpl::Load (LPCOLESTR szFile, DWORD mode)
  396. {
  397.         CAVIFile FAR    *p = m_pAVIFile;
  398.         UINT            ui;
  399.         char            ach[80];
  400.         char            szFileA[MAX_PATH];
  401.  
  402.         p->mode = mode;
  403.  
  404.         //
  405.         // Parse the filename
  406.         //
  407.         wsprintf(szFileA, "%ls", szFile);
  408.         p->dwFirstFrame = dseqParseFileName(szFileA,
  409.                                 p->achFilenameTemplate,
  410.                                 &p->dwMaxValue);
  411.  
  412.         //
  413.         // Initialize the variables that keep track of what frame is cached
  414.         //
  415.         p->lCurFrame = -1;
  416.         p->lpFrame = NULL;
  417.         p->cbFrame = 0;
  418.         p->cbFrameBuffer = 0;
  419.         p->lpFormat = NULL;
  420.         p->cbFormat = 0;
  421.         p->cbFormatBuffer = 0;
  422.  
  423.         //
  424.         // Build a stream header....
  425.         //
  426.         p->sinfo.fccType = streamtypeVIDEO;
  427.         p->sinfo.fccHandler = 0;
  428.         p->sinfo.dwFlags = 0;
  429.         p->sinfo.wPriority = 0;
  430.         p->sinfo.wLanguage = 0;
  431.         p->sinfo.dwInitialFrames = 0;
  432.         p->sinfo.dwScale = 1;
  433.         p->sinfo.dwRate = 15;
  434.         p->sinfo.dwStart = 0;
  435.         p->sinfo.dwLength = 0;
  436.         p->sinfo.dwSuggestedBufferSize = 0;
  437.         p->sinfo.dwSampleSize = 0;
  438.  
  439.         LoadString(ghModule, IDS_STREAMNAME, ach, sizeof(ach));
  440.         {
  441.             char TempFileName[80];
  442.             char TempName[80];
  443.             wsprintf(TempFileName, "%ls", szFile);
  444.             wsprintf(TempName, ach, FileName(TempFileName));
  445.             wsprintfW(p->sinfo.szName, L"%hs", TempName);
  446.         }
  447.  
  448.         //
  449.         // ... and a file header.
  450.         //
  451.         _fmemset(&p->finfo, 0, sizeof(p->finfo));
  452.         p->finfo.dwRate = 15;
  453.         p->finfo.dwScale = 1;
  454.         p->finfo.dwStreams = 1;
  455.         p->finfo.dwWidth = 0;
  456.         p->finfo.dwHeight = 0;
  457.         LoadString(ghModule, IDS_FILETYPE,
  458.                 p->finfo.szFileType,
  459.                 sizeof(p->finfo.szFileType));
  460.  
  461.         p->finfo.dwCaps = AVIFILECAPS_CANREAD |
  462.                                 AVIFILECAPS_CANWRITE |
  463.                                 AVIFILECAPS_ALLKEYFRAMES;
  464.  
  465.         if (mode & OF_CREATE) {
  466.         //
  467.         // They're creating a "new" sequence
  468.         //
  469.         p->fStreamPresent = FALSE;
  470.         } else {
  471.         char            ach[_MAX_PATH];
  472.         OFSTRUCT        of;
  473.         DWORD           dwFrame;
  474.         HRESULT         hr;
  475.  
  476.         //
  477.         // They're opening an existing sequence, so we have to actually
  478.         // count how many files are present
  479.         //
  480.         p->fStreamPresent = TRUE;
  481.  
  482.         ui = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  483.  
  484.         for (dwFrame = 0; TRUE; dwFrame++) {
  485.                 if (dwFrame > p->dwMaxValue)
  486.                 break;
  487.  
  488.                 wsprintf(ach,p->achFilenameTemplate, dwFrame + p->dwFirstFrame);
  489.  
  490.                 // DPF("DIBSEQ: Checking frame %lu from '%s'\n",dwFrame,(LPSTR) ach);
  491.  
  492. /****************************************************************************/
  493. /* DOS share has a bug.  If the file we're testing for existence is open    */
  494. /* already by someone else, we have to give it the same flag for SHARE as   */
  495. /* the other person is using.  So we have to try both on and off.  Only one */
  496. /* of these will return TRUE but if one of them does, the file exists.  Also*/
  497. /* we have to turn off the system model error box for share violations.     */
  498. /****************************************************************************/
  499.  
  500.                 if (OpenFile((LPSTR)ach, &of, OF_EXIST) == HFILE_ERROR &&
  501.                         OpenFile((LPSTR)ach, &of, OF_EXIST | OF_SHARE_DENY_NONE) ==
  502.                         HFILE_ERROR)
  503.                 break;
  504.         }
  505.  
  506.         SetErrorMode(ui);
  507.  
  508.         if (dwFrame == 0)
  509.                 goto error;
  510.  
  511.         //
  512.         // Fix up the length in the header structures
  513.         //
  514.         p->sinfo.dwLength = dwFrame;
  515.         p->finfo.dwLength = dwFrame;
  516.  
  517.         //
  518.         // Load the first frame, so we'll be ready...
  519.         //
  520.         hr = p->LoadFrame(0);
  521.  
  522.         if (FAILED(GetScode(hr)))
  523.                 return hr;
  524.  
  525.         p->finfo.dwSuggestedBufferSize = p->cbFrame;
  526.         p->sinfo.dwSuggestedBufferSize = p->cbFrame;
  527.  
  528.         p->finfo.dwWidth = ((LPBITMAPINFOHEADER) p->lpFormat)->biWidth;
  529.         p->finfo.dwHeight = ((LPBITMAPINFOHEADER) p->lpFormat)->biHeight;
  530.  
  531.         p->sinfo.dwFlags = AVISTREAMINFO_FORMATCHANGES;
  532.  
  533.         SetRect(&p->sinfo.rcFrame,
  534.                 0, 0, (int) p->finfo.dwWidth, (int) p->finfo.dwHeight);
  535.         }
  536.  
  537.         //
  538.         // all done return success.
  539.         //
  540.         return ResultFromScode(0); // success
  541.  
  542. error:
  543.         return ResultFromScode(AVIERR_FILEREAD);
  544.  
  545.  
  546. }
  547.  
  548.  
  549. STDMETHODIMP
  550. CAVIFile::CPersistFileImpl::Save (LPCOLESTR lpszFileName, BOOL fRemember)
  551. {
  552.         return ResultFromScode(AVIERR_UNSUPPORTED);
  553. }
  554.  
  555. STDMETHODIMP
  556. CAVIFile::CPersistFileImpl::SaveCompleted (LPCOLESTR lpszFileName)
  557. {
  558.         return NOERROR;
  559. }
  560.  
  561. STDMETHODIMP
  562. CAVIFile::CPersistFileImpl::GetCurFile (LPOLESTR FAR * lplpszFileName)
  563. {
  564.         return ResultFromScode(AVIERR_UNSUPPORTED);
  565. }
  566.  
  567.  
  568.  
  569. // -------------------- IAVIFile Implementation-----------------------
  570.  
  571.  
  572. //
  573. // The GetStream method returns an interface pointer to the video stream,
  574. // assuming one exists.
  575. //
  576. STDMETHODIMP CAVIFile::CAVIFileImpl::GetStream(
  577. PAVISTREAM FAR * ppavi,
  578. DWORD fccType,
  579. LONG lParam)
  580. {
  581.         CAVIFile FAR *  p = m_pAVIFile;
  582.         int             iStreamWant;
  583.  
  584.         iStreamWant = (int)lParam;
  585.  
  586.         if (!p->fStreamPresent)
  587.         return ResultFromScode(-1);
  588.  
  589.         // We only support one stream
  590.         if (lParam != 0)
  591.                 return ResultFromScode(-1);
  592.  
  593.         // We only support a video stream
  594.         if (fccType && fccType != streamtypeVIDEO)
  595.         return ResultFromScode(-1);
  596.  
  597.         //
  598.         // Be sure to keep the reference count up to date...
  599.         //
  600.         AddRef();
  601.  
  602.         *ppavi = (PAVISTREAM) &(p->m_AVIStream);
  603.         return ResultFromScode(AVIERR_OK);
  604. }
  605.  
  606.  
  607. //
  608. // If they opened the file with the OF_CREATE flag, they will use this
  609. // method to create the video stream.
  610. //
  611. STDMETHODIMP CAVIFile::CAVIFileImpl::CreateStream(
  612. PAVISTREAM FAR *ppstream,
  613. AVISTREAMINFOW FAR *psi
  614. )
  615. {
  616.         CAVIFile FAR *  p = m_pAVIFile;
  617.  
  618.         // If the stream was already there, we fail.
  619.         if (p->fStreamPresent)
  620.         return ResultFromScode(AVIERR_UNSUPPORTED);
  621.  
  622.         p->sinfo = *psi;
  623.         p->sinfo.dwLength = 0;
  624.  
  625.         *ppstream = (PAVISTREAM) &(p->m_AVIStream);
  626.         p->fStreamPresent = TRUE;
  627.  
  628.         // Keep the reference count correct
  629.         AddRef();
  630.  
  631.         return ResultFromScode(AVIERR_OK);
  632. }
  633.  
  634.  
  635. STDMETHODIMP CAVIFile::CAVIFileImpl::WriteData(
  636. DWORD ckid,
  637. LPVOID lpData,
  638. LONG cbData)
  639. {
  640.         CAVIFile FAR *  p = m_pAVIFile;
  641.  
  642.         return ResultFromScode(AVIERR_UNSUPPORTED);
  643. }
  644.  
  645. STDMETHODIMP CAVIFile::CAVIFileImpl::ReadData(
  646. DWORD ckid,
  647. LPVOID lpData,
  648. LONG FAR *lpcbData)
  649. {
  650.         CAVIFile FAR *  p = m_pAVIFile;
  651.  
  652.         return ResultFromScode(AVIERR_UNSUPPORTED);
  653. }
  654.  
  655. STDMETHODIMP CAVIFile::CAVIFileImpl::EndRecord(void)
  656. {
  657.         return ResultFromScode(AVIERR_OK);
  658. }
  659.  
  660.  
  661. STDMETHODIMP CAVIFile::CAVIFileImpl::Info(AVIFILEINFOW FAR * pfi, LONG lSize)
  662. {
  663.         CAVIFile FAR *  p = m_pAVIFile;
  664.  
  665.         hmemcpy(pfi, &p->finfo, min(lSize,sizeof(p->finfo)));
  666.         return 0;
  667. }
  668.  
  669.  
  670.  
  671. STDMETHODIMP CAVIFile::CAVIStreamImpl::Create(
  672. LONG lParam1,
  673. LONG lParam2)
  674. {
  675.         return ResultFromScode(AVIERR_UNSUPPORTED);
  676. }
  677.  
  678.  
  679. //
  680. // Returns where the last key frame before the given frame is.
  681. //
  682. // For now, we assume each DIB is a key frame.
  683. //
  684. STDMETHODIMP_(LONG) CAVIFile::CAVIStreamImpl::FindSample(
  685. LONG lPos,
  686. LONG lFlags)
  687. {
  688.         CAVIFile FAR * p = m_pAVIFile;
  689.  
  690.         // some minimal error checking....
  691.         if (lPos < 0 || lPos >= (LONG) p->sinfo.dwLength)
  692.         return -1;
  693.  
  694.         // !!! Can we really assume every frame is non-empty and a key frame?
  695.         // !!! Who knows where format changes are? Let's assume everywhere!
  696.  
  697.         return lPos;
  698. }
  699.  
  700. #define WIDTHBYTES(i)           ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  701. #define DIBWIDTHBYTES(bi)       (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  702. #define BFT_BITMAP              0x4d42   /* 'BM' */
  703.  
  704. //
  705. // Helper function to load a given frame into our cache.
  706. //
  707. // This is where the actual work is done; all other functions just return
  708. // the current format or frame out of the cache.
  709. //
  710. HRESULT NEAR PASCAL CAVIFile::LoadFrame(
  711. LONG lPos)
  712. {
  713.         char            ach[_MAX_PATH];
  714.         HMMIO           hmmio;
  715.         BITMAPFILEHEADER        bfh;
  716.         BITMAPINFOHEADER        bih;
  717.         SCODE           sc = 0;
  718.         UINT            ui;
  719.  
  720.         //
  721.         // Check if we've already loaded this frame...
  722.         //
  723.         if (lPos == lCurFrame)
  724.         return 0;
  725.  
  726.         //
  727.         // Build the filename by printing using our template
  728.         //
  729.         wsprintf(ach, achFilenameTemplate, dwFirstFrame + lPos);
  730.  
  731.         // No system error box, please.
  732.         ui = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  733.  
  734.         //
  735.         // Go try to read the frame... Because of SHARE we have to try
  736.         // opening it two different ways.
  737.         //
  738.         hmmio = mmioOpen(ach, NULL, MMIO_READ | OF_SHARE_DENY_WRITE);
  739.         if (!hmmio) {
  740.                 hmmio = mmioOpen(ach, NULL, MMIO_READ);
  741.         if (!hmmio)
  742.                 return ResultFromScode(AVIERR_FILEOPEN);
  743.         }
  744.  
  745.         SetErrorMode(ui);
  746.  
  747.         //
  748.         // Read the BitmapFileHeader...
  749.         //
  750.         if (mmioRead(hmmio, (LPSTR) &bfh, sizeof(bfh)) != sizeof(bfh)) {
  751.         sc = AVIERR_FILEREAD;
  752.         goto error;
  753.         }
  754.  
  755.         if (bfh.bfType != BFT_BITMAP) {
  756.         sc = AVIERR_BADFORMAT;
  757.         goto error;
  758.         }
  759.  
  760.         //
  761.         // Read the BitmapInfoHeader...
  762.         //
  763.         if (mmioRead(hmmio, (LPSTR) &bih, sizeof(bih)) != sizeof(bih)) {
  764.         sc = AVIERR_FILEREAD;
  765.         goto error;
  766.         }
  767.  
  768.         if (bih.biSize < sizeof(bih)) {
  769.         sc = AVIERR_BADFORMAT;
  770.         goto error;
  771.         }
  772.  
  773.         // Check that the width and height match....
  774.         if ((finfo.dwWidth && finfo.dwWidth != (DWORD) bih.biWidth) ||
  775.         (finfo.dwHeight && finfo.dwHeight != (DWORD) bih.biHeight)) {
  776.         sc = AVIERR_BADFORMAT;
  777.         goto error;
  778.         }
  779.  
  780.         // Fix up some fields in the header...
  781.         if (bih.biSizeImage == 0) {
  782.         bih.biSizeImage = DIBWIDTHBYTES(bih) * bih.biHeight;
  783.         }
  784.  
  785.         if (bih.biClrUsed == 0 && bih.biBitCount <= 8 && bih.biCompression <= BI_RLE8)
  786.         bih.biClrUsed = 1 << bih.biBitCount;
  787.  
  788.         cbFormat = bih.biSize + bih.biClrUsed * sizeof(RGBQUAD);
  789.  
  790.         // Allocate space for the format
  791.         if (cbFormat > cbFormatBuffer) {
  792.         if (lpFormat) {
  793.                 GlobalFreePtr(lpFormat);
  794.                 lpFormat = 0;
  795.                 cbFormatBuffer = 0;
  796.         }
  797.  
  798.         lpFormat = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_DDESHARE, cbFormat);
  799.         if (!lpFormat) {
  800.                 sc = AVIERR_MEMORY;
  801.                 goto error;
  802.         }
  803.  
  804.         cbFormatBuffer = cbFormat;
  805.         }
  806.  
  807.         *((LPBITMAPINFOHEADER) lpFormat) = bih;
  808.  
  809.         // If the format is bigger than a BITMAPINFOHEADER, read the rest....
  810.         if (cbFormat > sizeof(bih)) {
  811.         if (mmioRead(hmmio, (LPSTR) lpFormat + sizeof(bih),
  812.                 cbFormat - (LONG)sizeof(bih))
  813.                 != cbFormat - (LONG)sizeof(bih))
  814.         {
  815.                 sc = AVIERR_FILEREAD;
  816.                 goto error;
  817.         }
  818.         }
  819.  
  820.         //
  821.         // Allocate enough space to read the frame in...
  822.         //
  823.         if (bih.biSizeImage > (DWORD) cbFrameBuffer) {
  824.         if (lpFrame) {
  825.                 GlobalFreePtr(lpFrame);
  826.                 lpFrame = 0;
  827.                 cbFrameBuffer = 0;
  828.         }
  829.  
  830.         lpFrame = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_DDESHARE, bih.biSizeImage);
  831.         if (!lpFrame) {
  832.                 sc = AVIERR_MEMORY;
  833.                 goto error;
  834.         }
  835.  
  836.         cbFrameBuffer = bih.biSizeImage;
  837.         }
  838.  
  839.         cbFrame = bih.biSizeImage;
  840.  
  841.         //
  842.         // and actually read the frame....
  843.         //
  844.         if (mmioRead(hmmio, (LPSTR) lpFrame, cbFrame) != cbFrame) {
  845.         sc = AVIERR_FILEREAD;
  846.         goto error;
  847.         }
  848.  
  849.         lCurFrame = lPos;
  850.  
  851. error:
  852.         mmioClose(hmmio, 0);
  853.  
  854.         return ResultFromScode(sc);
  855. }
  856.  
  857. //
  858. // The ReadFormat method returns the format of the specified frame....
  859. //
  860. STDMETHODIMP CAVIFile::CAVIStreamImpl::ReadFormat(
  861. LONG lPos,
  862. LPVOID lpFormat,
  863. LONG FAR *lpcbFormat)
  864. {
  865.         CAVIFile FAR * p = m_pAVIFile;
  866.         HRESULT hr;
  867.  
  868.         //
  869.         // Try to get the correct frame
  870.         //
  871.         hr = p->LoadFrame(lPos);
  872.  
  873.         if (hr != 0)
  874.         return hr;
  875.  
  876.         // No buffer to fill in, this means return the size needed.
  877.         if (lpFormat == NULL || *lpcbFormat == 0) {
  878.                 *lpcbFormat = p->cbFormat;
  879.         return 0;
  880.         }
  881.  
  882.         //
  883.         // and return as much of the format as will fit.
  884.         //
  885.         hmemcpy(lpFormat, p->lpFormat, min(*lpcbFormat, p->cbFormat));
  886.         *lpcbFormat = p->cbFormat;
  887.         return 0;
  888. }
  889.  
  890. ///////////////////////////////////////////////////////////////////////////
  891. ///////////////////////////////////////////////////////////////////////////
  892.  
  893.  
  894. STDMETHODIMP CAVIFile::CAVIStreamImpl::Info(AVISTREAMINFOW FAR * psi, LONG lSize)
  895. {
  896.         CAVIFile FAR * p = m_pAVIFile;
  897.  
  898.         hmemcpy(psi,&p->sinfo, min(lSize,sizeof(p->sinfo)));
  899. //      return sizeof(p->sinfo);
  900.         return 0;
  901. }
  902.  
  903. STDMETHODIMP_(ULONG) CAVIFile::CUnknownImpl::Release()
  904. {
  905.         CAVIFile FAR * p = m_pAVIFile;
  906.  
  907.         uUseCount--;
  908.         if (!--m_refs) {
  909.         LONG lRet = AVIERR_OK;
  910.  
  911.         if (p->fDirty) {
  912.         }
  913.  
  914.  
  915.         goto success;
  916.  
  917.         success:
  918.         if (p->lpFormat)
  919.                 GlobalFreePtr(p->lpFormat);
  920.  
  921.         p->lpFormat = NULL;
  922.         p->cbFormat = 0;
  923.  
  924.         if (p->lpFrame)
  925.                 GlobalFreePtr(p->lpFrame);
  926.  
  927.         p->lpFrame = NULL;
  928.         p->cbFrame = 0;
  929.  
  930.         delete this;
  931.         return 0;
  932.         }
  933.         return m_refs;
  934. }
  935.  
  936.  
  937. ///////////////////////////////////////////////////////////////////////////
  938. ///////////////////////////////////////////////////////////////////////////
  939.  
  940.  
  941. STDMETHODIMP CAVIFile::CAVIStreamImpl::Read(
  942. LONG            lStart,
  943. LONG            lSamples,
  944. LPVOID          lpBuffer,
  945. LONG            cbBuffer,
  946. LONG FAR *      plBytes,
  947. LONG FAR *      plSamples)
  948. {
  949.         CAVIFile FAR *  p = m_pAVIFile;
  950.         HRESULT     hr;
  951.  
  952.         if (lStart < 0 || lStart >= (LONG) p->sinfo.dwLength) {
  953.         if (plBytes)
  954.             *plBytes = 0;
  955.         if (plSamples)
  956.             *plSamples = 0;
  957.         return 0;
  958.         }
  959.  
  960.         // We always read one frame at a time...
  961.         lSamples = 1;
  962.  
  963.         // Load it into the cache....
  964.         hr = p->LoadFrame(lStart);
  965.  
  966.         if (hr != 0)
  967.         return hr;
  968.  
  969.         //
  970.         // a NULL buffer means return the size buffer needed to read
  971.         // the given sample.
  972.         //
  973.         if (lpBuffer == NULL || cbBuffer == 0) {
  974.         if (plBytes)
  975.             *plBytes =  p->cbFrame;
  976.         if (plSamples)
  977.             *plSamples = lSamples;
  978.         return 0;
  979.         }
  980.  
  981.         //
  982.         // They didn't give us enough space for the frame, so complain
  983.         //
  984.         if (cbBuffer < p->cbFrame) {
  985.         if (plBytes)
  986.             *plBytes = p->cbFrame;
  987.  
  988.         return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  989.         }
  990.  
  991.         //
  992.         // Copy the frame into the caller's buffer
  993.         //
  994.         hmemcpy(lpBuffer, p->lpFrame, p->cbFrame);
  995.  
  996.         //
  997.         // success return number of bytes and number of samples read
  998.         //
  999.         if (plBytes)
  1000.                 *plBytes = p->cbFrame;
  1001.  
  1002.         if (plSamples)
  1003.                 *plSamples = lSamples;
  1004.  
  1005.         return ResultFromScode(AVIERR_OK);
  1006. }
  1007.  
  1008.  
  1009. STDMETHODIMP CAVIFile::CAVIStreamImpl::SetFormat(
  1010. LONG lPos,
  1011. LPVOID lpFormat,
  1012. LONG cbFormat)
  1013. {
  1014.         CAVIFile FAR * p = m_pAVIFile;
  1015.  
  1016.         // Keep track of the format....
  1017.         p->cbFormat = cbFormat;
  1018.         p->lpFormat = (LPVOID) GlobalAllocPtr(GMEM_MOVEABLE | GMEM_DDESHARE, cbFormat);
  1019.  
  1020.         if (p->lpFormat == NULL)
  1021.         return ResultFromScode(AVIERR_MEMORY);
  1022.  
  1023.         hmemcpy(p->lpFormat, lpFormat, cbFormat);
  1024.  
  1025.         p->finfo.dwWidth = ((LPBITMAPINFOHEADER) p->lpFormat)->biWidth;
  1026.         p->finfo.dwHeight = ((LPBITMAPINFOHEADER) p->lpFormat)->biHeight;
  1027.  
  1028.         SetRect(&p->sinfo.rcFrame,
  1029.             0, 0, (int) p->finfo.dwWidth, (int) p->finfo.dwHeight);
  1030.  
  1031.         return 0L;
  1032. }
  1033.  
  1034. //
  1035. // Helper function to save a single frame
  1036. //
  1037. HRESULT NEAR PASCAL CAVIFile::WriteFrame(
  1038. LONG lPos,
  1039. LPVOID lp,
  1040. LONG cb)
  1041. {
  1042.         char            ach[_MAX_PATH];
  1043.         HMMIO           hmmio;
  1044.         BITMAPFILEHEADER        bfh;
  1045.  
  1046.         //
  1047.         // If they're overwriting the cached frame, invalidate the cache
  1048.         //
  1049.         if (lPos == lCurFrame)
  1050.         lCurFrame = -1;
  1051.  
  1052.  
  1053.         //
  1054.         // Build the filename to write to
  1055.         //
  1056.         wsprintf(ach, achFilenameTemplate, dwFirstFrame + lPos);
  1057.  
  1058.         // and write it.
  1059.         hmmio = mmioOpen(ach, NULL, MMIO_WRITE | MMIO_CREATE | OF_SHARE_EXCLUSIVE);
  1060.  
  1061.         if (!hmmio)
  1062.         return ResultFromScode(AVIERR_FILEOPEN);
  1063.  
  1064.         //
  1065.         // Write the BitmapFileHeader
  1066.         //
  1067.         bfh.bfType = BFT_BITMAP;
  1068.         bfh.bfOffBits = sizeof(bfh) + cbFormat;
  1069.         bfh.bfSize = bfh.bfOffBits + cb;
  1070.  
  1071.         if (mmioWrite(hmmio, (LPSTR) &bfh, sizeof(bfh)) != sizeof(bfh)) {
  1072. error:
  1073.         mmioClose(hmmio, 0);
  1074.         return ResultFromScode(AVIERR_FILEWRITE);
  1075.         }
  1076.  
  1077.         ((LPBITMAPINFOHEADER) lpFormat)->biSizeImage = cb;
  1078.  
  1079.         //
  1080.         // Write the DIB format
  1081.         //
  1082.         if (mmioWrite(hmmio, (LPSTR) lpFormat, cbFormat) != cbFormat)
  1083.         goto error;
  1084.  
  1085.         //
  1086.         // Write the data
  1087.         //
  1088.         if (mmioWrite(hmmio, (LPSTR) lp, cb) != cb)
  1089.         goto error;
  1090.  
  1091.         //
  1092.         // Flush things so that we can be sure everything is written out
  1093.         //
  1094.         if (mmioFlush(hmmio, 0) != 0)
  1095.         goto error;
  1096.  
  1097.         mmioClose(hmmio, 0);
  1098.  
  1099.         return 0;
  1100. }
  1101.  
  1102. STDMETHODIMP CAVIFile::CAVIStreamImpl::Write(
  1103. LONG lStart,
  1104. LONG lSamples,
  1105. LPVOID lpData,
  1106. LONG cbData,
  1107. DWORD dwFlags,
  1108. LONG FAR *plSampWritten,
  1109. LONG FAR *plBytesWritten)
  1110. {
  1111.         CAVIFile FAR *  p = m_pAVIFile;
  1112.         HRESULT     hr;
  1113.  
  1114.         if ((p->mode & (OF_WRITE | OF_READWRITE)) == 0)
  1115.         return ResultFromScode(AVIERR_READONLY);
  1116.  
  1117.         if (p->lpFormat == NULL)
  1118.         return ResultFromScode(AVIERR_UNSUPPORTED);
  1119.  
  1120.         // < 0 means "at end"
  1121.         if (lStart < 0)
  1122.         lStart = p->sinfo.dwStart + p->sinfo.dwLength;
  1123.  
  1124.         if (lStart > (LONG) (p->sinfo.dwStart + p->sinfo.dwLength))
  1125.         return ResultFromScode(AVIERR_BADPARAM);
  1126.  
  1127.         // !!! Die if we've reached the limit of our numbers....
  1128.         if ((DWORD) lStart + p->dwFirstFrame > p->dwMaxValue)
  1129.         return ResultFromScode(AVIERR_FILEWRITE);
  1130.  
  1131.         if (lSamples != 1)
  1132.         return ResultFromScode(AVIERR_BADPARAM);
  1133.  
  1134.         // only allow key frames!
  1135.         if (!(dwFlags & AVIIF_KEYFRAME)) {
  1136.         DPF("Tried to write a non-key frame to a DIB sequence!\n");
  1137.         return ResultFromScode(AVIERR_UNSUPPORTED);
  1138.         }
  1139.  
  1140.         hr = p->WriteFrame(lStart, lpData, cbData);
  1141.  
  1142.         if (hr != AVIERR_OK)
  1143.         return hr;
  1144.  
  1145.         p->fDirty = TRUE;
  1146.  
  1147.         p->sinfo.dwLength =
  1148.                 max((LONG) p->sinfo.dwLength,
  1149.                                   lStart + lSamples);
  1150.  
  1151.         p->finfo.dwLength = p->sinfo.dwLength;
  1152.  
  1153.         p->finfo.dwSuggestedBufferSize =
  1154.                         max(p->finfo.dwSuggestedBufferSize, (DWORD) cbData);
  1155.         p->sinfo.dwSuggestedBufferSize =
  1156.                         p->finfo.dwSuggestedBufferSize;
  1157.  
  1158.         if (plSampWritten)
  1159.         *plSampWritten = lSamples;
  1160.  
  1161.         if (plBytesWritten)
  1162.         *plBytesWritten = cbData;
  1163.  
  1164.         return ResultFromScode(AVIERR_OK);
  1165. }
  1166.  
  1167. // these both are for saving. we don't support saving
  1168.  
  1169. STDMETHODIMP
  1170. CAVIFile::CAVIFileImpl::DeleteStream(DWORD fccType, LONG lParam)
  1171. {
  1172.     return ResultFromScode(E_FAIL);
  1173. }
  1174.  
  1175. STDMETHODIMP
  1176. CAVIFile::CAVIStreamImpl::SetInfo(
  1177.                 AVISTREAMINFOW FAR * lpInfo,
  1178.                 LONG cbInfo
  1179. )
  1180. {
  1181.     return ResultFromScode(E_FAIL);
  1182. }
  1183.  
  1184.  
  1185. STDMETHODIMP CAVIFile::CAVIStreamImpl::Delete(
  1186. LONG lStart,
  1187. LONG lSamples)
  1188. {
  1189.         CAVIFile FAR * p = m_pAVIFile;
  1190.  
  1191.         return ResultFromScode(AVIERR_UNSUPPORTED);
  1192. }
  1193.  
  1194.  
  1195. // Should these just map to Read/WriteData? !!!
  1196.  
  1197. STDMETHODIMP CAVIFile::CAVIStreamImpl::ReadData(
  1198. DWORD fcc,
  1199. LPVOID lp,
  1200. LONG FAR *lpcb)
  1201. {
  1202.         CAVIFile FAR * p = m_pAVIFile;
  1203.  
  1204.         return ResultFromScode(AVIERR_UNSUPPORTED);
  1205. }
  1206.  
  1207. STDMETHODIMP CAVIFile::CAVIStreamImpl::WriteData(
  1208. DWORD fcc,
  1209. LPVOID lp,
  1210. LONG cb)
  1211. {
  1212.         CAVIFile FAR * p = m_pAVIFile;
  1213.  
  1214.         return ResultFromScode(AVIERR_UNSUPPORTED);
  1215. }
  1216.  
  1217.  
  1218. #ifdef CUSTOMMARSHAL
  1219. // The code below supports custom marshalling.
  1220.  
  1221. // !!! Need good explanation here!
  1222.  
  1223. CAVIFile::CMarshalImpl::CMarshalImpl(
  1224. CAVIFile FAR*   pAVIFile)
  1225. {
  1226.         m_pAVIFile = pAVIFile;
  1227. }
  1228.  
  1229. /*      -       -       -       -       -       -       -       -       */
  1230.  
  1231. STDMETHODIMP CAVIFile::CMarshalImpl::QueryInterface(
  1232. const IID FAR&  iid,
  1233. void FAR* FAR*  ppv)
  1234. {
  1235.         return m_pAVIFile->m_pUnknownOuter->QueryInterface(iid, ppv);
  1236. }
  1237.  
  1238. /*      -       -       -       -       -       -       -       -       */
  1239.  
  1240. STDMETHODIMP_(ULONG) CAVIFile::CMarshalImpl::AddRef()
  1241. {
  1242.         return m_pAVIFile->m_pUnknownOuter->AddRef();
  1243. }
  1244.  
  1245. /*      -       -       -       -       -       -       -       -       */
  1246.  
  1247. STDMETHODIMP_(ULONG) CAVIFile::CMarshalImpl::Release()
  1248. {
  1249.         return m_pAVIFile->m_pUnknownOuter->Release();
  1250. }
  1251.  
  1252. // *** IMarshal methods ***
  1253. STDMETHODIMP CAVIFile::CMarshalImpl::GetUnmarshalClass (
  1254. THIS_ REFIID riid, LPVOID pv,
  1255. DWORD dwDestContext, LPVOID pvDestContext,
  1256. DWORD mshlflags, LPCLSID pCid)
  1257. {
  1258.         HRESULT hr = NOERROR;
  1259.  
  1260.         DPF("UnMarshalClass called\n");
  1261.  
  1262.         if (dwDestContext != MSHCTX_LOCAL) {
  1263.         LPMARSHAL       pMarshal;
  1264.  
  1265.         DPF("Marshal context is %lu: delegating...\n", dwDestContext);
  1266.  
  1267.         hr = CoGetStandardMarshal(riid, NULL, dwDestContext, pvDestContext, mshlflags,
  1268.                         &pMarshal);
  1269.  
  1270.         if (hr != NOERROR)
  1271.                 return hr;
  1272.  
  1273.         hr = pMarshal->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext,
  1274.                         mshlflags, pCid);
  1275.  
  1276.         pMarshal->Release();
  1277.  
  1278.         return hr;
  1279.         }
  1280.  
  1281.         *pCid = CLSID_AVISimpleUnMarshal;
  1282.  
  1283.         return hr;
  1284. }
  1285.  
  1286. STDMETHODIMP CAVIFile::CMarshalImpl::GetMarshalSizeMax (
  1287. THIS_ REFIID riid, LPVOID pv,
  1288. DWORD dwDestContext, LPVOID pvDestContext,
  1289. DWORD mshlflags, LPDWORD pSize)
  1290. {
  1291.         HRESULT hr = NOERROR;
  1292.         IUnknown FAR * pUnk = &m_pAVIFile->m_Unknown;
  1293.  
  1294.         if (dwDestContext != MSHCTX_LOCAL) {
  1295.         LPMARSHAL       pMarshal;
  1296.  
  1297.         hr = CoGetStandardMarshal(riid, NULL, dwDestContext, pvDestContext, mshlflags,
  1298.                 &pMarshal);
  1299.  
  1300.         if (hr != NOERROR)
  1301.                 return hr;
  1302.  
  1303.         hr = pMarshal->GetMarshalSizeMax(riid, pv, dwDestContext, pvDestContext,
  1304.                         mshlflags, pSize);
  1305.  
  1306.         pMarshal->Release();
  1307.  
  1308.         return hr;
  1309.         }
  1310.  
  1311.         *pSize = sizeof(pUnk);
  1312.  
  1313.         return hr;
  1314. }
  1315.  
  1316. STDMETHODIMP CAVIFile::CMarshalImpl::MarshalInterface (
  1317. THIS_ LPSTREAM pStm, REFIID riid,
  1318. LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,
  1319. DWORD mshlflags)
  1320. {
  1321.         HRESULT hr = NOERROR;
  1322.         IUnknown FAR * pUnk = &m_pAVIFile->m_Unknown;
  1323.  
  1324.         DPF("MarshalInterface called\n");
  1325.  
  1326.         if (dwDestContext != MSHCTX_LOCAL) {
  1327.         LPMARSHAL pMarshal;
  1328.  
  1329.         DPF("Marshal context is %lu: delegating...\n", dwDestContext);
  1330.  
  1331.         hr = CoGetStandardMarshal(riid, NULL, dwDestContext, pvDestContext, mshlflags,
  1332.                 &pMarshal);
  1333.  
  1334.         if (hr != NOERROR)
  1335.                 return hr;
  1336.  
  1337.         hr = pMarshal->MarshalInterface(pStm, riid, pv, dwDestContext, pvDestContext,
  1338.                         mshlflags);
  1339.  
  1340.         pMarshal->Release();
  1341.  
  1342.         return hr;
  1343.         }
  1344.  
  1345.  
  1346.         if ((riid != IID_IAVIStream && riid != IID_IAVIFile && riid != IID_IUnknown))
  1347.                 return ResultFromScode(E_INVALIDARG);
  1348.  
  1349.         if ((hr = pStm->Write(&pUnk, sizeof(pUnk), NULL)) == NOERROR)
  1350.         AddRef();
  1351.  
  1352.         DPF("Returns %lx\n", (DWORD) (LPVOID) hr);
  1353.         return hr;
  1354. }
  1355.  
  1356. STDMETHODIMP CAVIFile::CMarshalImpl::UnmarshalInterface (
  1357. THIS_ LPSTREAM pStm, REFIID riid,
  1358. LPVOID FAR* ppv)
  1359. {
  1360.         HRESULT hr = ResultFromScode(E_FAIL);
  1361.  
  1362.         DPF("UnMarshalInterface called!!!\n");
  1363.         return hr;
  1364. }
  1365.  
  1366. STDMETHODIMP CAVIFile::CMarshalImpl::ReleaseMarshalData (
  1367. THIS_ LPSTREAM pStm)
  1368. {
  1369.         HRESULT hr = NOERROR;
  1370.         IUnknown FAR * pUnk;
  1371.  
  1372.         hr = pStm->Read(&pUnk,sizeof(pUnk),NULL);
  1373.         if (hr == NOERROR)
  1374.         pUnk->Release();
  1375.  
  1376.         return hr;
  1377. }
  1378.  
  1379. STDMETHODIMP CAVIFile::CMarshalImpl::DisconnectObject (
  1380. THIS_ DWORD dwReserved)
  1381. {
  1382.         HRESULT hr = NOERROR;
  1383.  
  1384.         return hr;
  1385. }
  1386. #endif
  1387.  
  1388. /*****************************************************************************
  1389.  *
  1390.  * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  1391.  *
  1392.  * The messages will be send to COM1: like any debug message. To
  1393.  * enable debug output, add the following to WIN.INI :
  1394.  *
  1395.  * [debug]
  1396.  * ICSAMPLE=1
  1397.  *
  1398.  ****************************************************************************/
  1399.  
  1400. #ifdef DEBUG
  1401.  
  1402. #define MODNAME "DSEQFILE"
  1403. static BOOL fDebug = -1;
  1404.  
  1405. static void cdecl dprintf(
  1406. LPSTR szFormat, ...)
  1407. {
  1408.         char ach[128];
  1409.  
  1410.         va_list va;
  1411.         if (fDebug == -1)
  1412.                 fDebug = GetProfileIntA("Debug",MODNAME, FALSE);
  1413.  
  1414.         if (!fDebug)
  1415.                 return;
  1416.  
  1417.         va_start(va, szFormat);
  1418.         if (szFormat[0] == '!')
  1419.                 ach[0]=0, szFormat++;
  1420.         else
  1421.                 lstrcpyA(ach, MODNAME ": ");
  1422.  
  1423.         wvsprintfA(ach+lstrlenA(ach),szFormat,(LPSTR)va);
  1424.         va_end(va);
  1425. //      lstrcatA(ach, "\r\r\n");
  1426.  
  1427.         OutputDebugStringA(ach);
  1428. }
  1429.  
  1430. #endif
  1431.