Link to home
Start Free TrialLog in
Avatar of aejones
aejones

asked on

Quicktime in MFC: Getting AccessViolation/first-chance exception

I gave up trying to search this site for related questions -- decided to just ask my own Q and see if I get a response.  I am pretty desperate for help.

I am working on a form-view based application that loads Quicktime movies and rtf files.  I am able to load and display the text files in a RichEditCtrl with no problems.  I can load a single-frame movie repeatedly with no problems, using both a hand-rolled QT-wrapper class and a commercial ActiveX QT player.  

The problem is, when I load the 'real' videos, I get a fairly consistent access violation.  The way the program works is it switches between 3 modes -- text, sign-language video, and animation video (both in QT format).  After loading a few videos and/or switching between text and video mode, it almost always crashes (running in Debug mode).

I had been optimistic that using a commercial QT player would solve the problem, but it did not help.  When the crash occurs, the call stack always shows the following:

KERNEL32! bff7a606()
WINMM! bfdf67f1()
KERNEL32! bff958f8()
00737472()

And VC++ always breaks into disassembly garbage that I can't decipher.

I have set breakpoints up the wazoo trying to isolate what sets it off, but it seems to happen after any of my code is run.  Obviously memory is being overwritten somewhere and it doesn't crash until a bit later, and it seems to be related to opening movie files, but how can I isolate it further? (And ultimately fix it?)

Thanks in advance for any help or suggestions..
--aejones
Avatar of ShaunWilde
ShaunWilde

Do you have example code? - it would take the experts some time to recreate your scenario and it ould be quicker if you could do that and post it to anyone who asks
Avatar of aejones

ASKER

Good idea.  I will post the relevant functions in separate comments.

The functions I think are related to the bug are:

LoadVideo(CString):  loads a QT file given its filename

LoadText(CString):  loads an RTF file given its filename

OnBtnASL():  sets up controls on screen for sign-lang vid, calls LoadVideo()

OnBtnAnim():  sets up controls on screen for animation vid, calls LoadVideo()

OnBtnText():  sets up controls on screen for RTF file, calls LoadText()

(function bodies to follow)
Avatar of aejones

ASKER

void CDMCReview::LoadVideo(CString strFilename)
{
     CString strFullFilename, strPath, strTemp, strDefaultVidFile;
     char buff[3];

     // check to see if the target file exists
     HANDLE hFileHandle;    
     WIN32_FIND_DATA FindFileData;

     strFullFilename = m_strMediaPath;
     strFullFilename += "\Lesson_";  
     strFullFilename += (CString)itoa(m_nCurrLesson + 1, buff, 10);
     strFullFilename += (CString)"\\";
     strFullFilename += strFilename;

     strDefaultVidFile = m_strMediaPath;
     strDefaultVidFile +="\\noVid.mov";

     m_txtCurrFile.SetWindowText(strFilename);

     hFileHandle = ::FindFirstFile((LPCTSTR)strFullFilename, &FindFileData);
     bool fileFound = (hFileHandle != INVALID_HANDLE_VALUE);
     ::FindClose(hFileHandle);
     
     m_btnRepeat.EnableWindow(TRUE);

     if(fileFound)
     {
          m_ctrlSkyVid.SetFileName(strFullFilename);
     }
     else
     {
          CString err = "Video file ";
          err + strFullFilename;
          err += " not found!";
          AfxMessageBox(err, 0, 0);
          m_ctrlSkyVid.SetFileName(strDefaultVidFile);
     }
     
     m_ctrlSkyVid.Play();

}
Avatar of aejones

ASKER

void CDMCReview::LoadText(CString strFilename)
{
     char buff[3];
     CString strMsg, strErr, strDefaultTxt;
      CString strCurrFile, strFullPath;
     CString strCurrIndex, strCurrPart;

     m_ctrlSkyVid.ShowWindow(SW_HIDE);

     m_txtSystem.ShowWindow(SW_HIDE);
     m_imgReviewBanner.ShowWindow(SW_SHOW);
     m_ctrlPresentText.ShowWindow(SW_SHOW);

     strFullPath = m_strMediaPath;  
 
     // set up default text file for missing resource...
     strDefaultTxt = strFullPath;
     strDefaultTxt += "noTxt.rtf";    

     strFullPath += "Lesson_";

     if (m_bRevMode)
          strFullPath += itoa(m_nCurrLesson, buff, 10);
     else
          strFullPath += itoa((m_nCurrLesson + 1), buff, 10);
     strFullPath += "\\";
     strFullPath += strFilename;

      // determine if file is present
      HANDLE hFileHandle;
      WIN32_FIND_DATA fd;
      hFileHandle = ::FindFirstFile((LPCTSTR)strFullPath, &fd);
      bool FileExists = (hFileHandle != INVALID_HANDLE_VALUE);
      ::FindClose(hFileHandle);
 
      CFile cFile;
 
      if(FileExists)
     {
           cFile.Open((LPCTSTR)strFullPath, CFile::modeRead);
     }
      else          
     {
          CString strErr = "Error:  Missing file: ";
          strErr += strFilename;
          AfxMessageBox(strErr, 0, 0);
          cFile.Open((LPCTSTR)strDefaultTxt, CFile::modeRead);
     }

     m_txtCurrFile.SetWindowText(strFilename);
     

     EDITSTREAM es;
      es.dwCookie = (DWORD) &cFile;
      es.pfnCallback = PullTextFromFileRev;

     // Turn word wrap on - based on window width
     m_ctrlPresentText.SetTargetDevice(NULL, 1);
     
      m_ctrlPresentText.StreamIn(SF_RTF, es);
}
Avatar of aejones

ASKER

void CDMCReview::OnBtnAnim()
{
     CString strFilename;

     m_ctrlSkyVid.Stop();

     m_imgReviewBanner.ShowWindow(SW_HIDE);
     m_txtSystem.ShowWindow(SW_HIDE);
     m_ctrlPresentText.ShowWindow(SW_HIDE);
     m_ctrlSkyVid.ShowWindow(SW_SHOW);  

     m_btnRepeat.EnableWindow(TRUE);
     m_btnText.EnableWindow(TRUE);
     m_btnAnim.EnableWindow(FALSE);   // they should not be able to push this again...
     m_btnASL.EnableWindow(TRUE);
     m_bSeenAnim = true;
     m_btnText.SetCheck(0);
     m_btnASL.SetCheck(0);

     m_btnContinue.EnableWindow(TRUE);

     // load current Anim item
     strFilename = LookupTriplet(m_nCurrLesson, m_nCurrCluster, m_nCurrTriplet, m_bRevMode, 'N');
     LoadVideo(strFilename);
}

Note:  This function is nearly identical to OnBtnASL() and OnBtnText()...if you need the specifics on those other 2, let me know and I will post them as well.
what is m_ctrlSkyVid ?
Avatar of aejones

ASKER

It's an ActiveX control that loads the videos.  (Skylight control downloaded from a 3rd party site -- www.skylight.ie).  

Previously, I was using a 'hand-rolled' QT wrapper class written by a former colleague -- but I replaced it recently with the Skylight control thinking the homemade control may have been the culprit, perhaps not allocating or releasing memory properly.  Since replacing it had no visible impact on the bug, it either means the problem is related to the underlying QT library classes (since they both rely on these), or that the problem is not directly related to the movie loading mechanism...


are you using the demo? It says that the demo control is limited on the number of files you can open - wild guess here
Avatar of aejones

ASKER

I am currently using the demo, but it happens before the 10-file maximum is reached.  It was also occurring before, using the homemade QT wrapper class to load the videos.

Besides, it would be pretty bad PR if, after exceeding the number of files allowed, it simply crashed the entire program...(and occasionally brought down my entire machine), don't you think?  ;-)

Thanks for the updated link, btw...
> , it would be pretty bad PR

yup :) as I said wild guess
Avatar of DanRollins
One way to attack:  
Isolate it so that only the video is at issue -- that is, stub out all of the text-screen related fns and see if the problem continues.

Next tack:
Spinkle a bunch of TRACE statements around to see how far things go before the crash
TRACE("calling LoadVideo\r\n");
TRACE("Starting playback\r\n");
TRACE("Stopping playback\r\n");
TRACE("unloading the video\r\n");
etc.

I also see that you are not checking return (error?) codes from calls such as m_ctrlSkyVid.Stop(); and Play() and LookupTriplet (whatever that is).

It might be that the video activeX has not completely shutdown playback when you start to play again.  Are there some events you can trap to ensure that playback is stopped before calling Play()?

-- Dan
Avatar of aejones

ASKER

Thanks for the comments...I will try adding TRACE statements, and checking the return codes from the video control functions.  

I am sure playback is shutdown before calling Play again because I manually call m_ctrlSkyVid.Stop().  I have looked at the documentation for the control itself and for the Quicktime libraries and this should be fine.  
Avatar of aejones

ASKER

Thanks again for the suggestions.  I tried using TRACE statements, but that isolated it down to something that made no sense -- the call to SkyVid.SetFileName().  Since the bug was happening before I introduced the SkyVid control, this seemed to confirm my earlier suspicion that something was getting corrupted earlier on.

I decided to use HeapAgent (an interactive mem error debug tool) to try to figure out where the corruption might be occurring...but strangely enough, it did not pick up the bug -- in fact, it did not occur at all when running through HA!

I removed HeapAgent from my system to see if the bug returned, and so far it has not...even in Release mode.

I'm cautiously optimistic (but still somewhat paranoid about the problem's pretty random appearance and disappearance).  For now I think I will keep this question open for a while in case the bug comes back...at least in that case there will be a record of the problem here.

In the meantime, DanRollins, I will post points for you in the CS area because your suggestions were helpful (good general debugging strategies that I'm sure I will use in the future).

--aej
Thanks aejones.

CS deleted your "Points for DanROllins" question.  I'd prefer them in MFC section anyway.

Incidently, if the error is related to the filename, it might help to use code like:

void CDMCReview::LoadVideo( LPCSTR szFilename)
{
    CString strFilename= szFilename;
...

This is the normal way for a function to "recieve" a CString --- they are only rarely passed as a CString (perhaps a CString& or a CString* ...);

Also, I don't know the SkyVid interface, but there is a chance that it is not making a copy of the filename and that it relies on you passing a persistant buffer.  That would cause unpredictable results like you have seen.

Since the problem is no longer reproducible, these theories are hard to test.  However, code such as

    static char szFile[255];
    strcpy(szFile, strFuleFilename);
    m_ctrlSkyVid.SetFileName( szFile );

...would be one avenue of approach.

-- Dan
Avatar of aejones

ASKER

OK, there is now a points-question for you in the MFC area.  (Sorry, it had been a while since I participated in EE and I had forgotten the standard protocol...) :-)

Regarding your comments about passing CStrings by value, I think you may be mistaken there...

This is the 3rd program in a suite of similar products, each of which contains at least a hundred functions accepting CString arguments.  Never had a problem as a result.

There is an interesting discussion of CStrings on CodeGuru:

http://www.codeguru.com/string/CStringInANutshell.shtml

Thanks again for your comments!
--aej
after downloading from
  http://www.skylark.ie/skylight/index.htm
I see that in the MFC demo, they use code such as:

TCHAR szFile[256];
...
m_ctlSkyLight1.SetFileName(szFile);

strcpy( szFile, m_ctlSkyLight1.GetFileName() );
e = m_ctlSkyLight1.GetErrorCode();

When QuickTime is not installed, (or perhaps when the file is not found), the return code is 0 (no error) and szFile ends up as "".  

The fact that they placed this code (the call to GetFileName) into the demo is an implied suggestion that checking the filename after SetFileName is good idea:

if( !fileFound ) {
   CString sErr;
   sErr.Format( "Video file %s not found", (LPCSTR)strFullFilename );
   AfxMessageBox( sErr );
   strFullFilename= strDefaultVidFile;
}
m_ctrlSkyVid.SetFileName(strFullFilename);
CString sTmp= m_ctrlSkyVid.GetFileName();
ASSERT( sTmp != "" );

=-=-=-=-=-=-=-=-=-
>>passing CStrings by value, I think you may be mistaken there...

That is a good, informative article.  But when passing a CString by value, the CString copy ctor needs to be called, which is possibly somewhat less efficient than using the LPCSTR cast (which boils down to passing a pointer directly to the data)

Why doesn't MFC itself use this technique (passing CString by value to any of its class members)?  Perhaps it is legacy code from when CString was a less robust class.  Or perhaps they want to avoid that call to InterlockedDecrement and thereby avoid some thread-safety issues.

However, having seen the SkyLight wrapper code, I agree that it is unlikely that your problem is related to persistance of the filename.

-- Dan
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

PAQ'd and pts refunded

Please leave any comments here within the next seven days.

PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!

Roshan Davis
EE Cleanup Volunteer
ASKER CERTIFIED SOLUTION
Avatar of Computer101
Computer101
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial