0

WinAPI で JEDI ラッパーの VFW ユニットを使用しています。

私が書いているコードは、ユーザーのドライブを検索してウェアーズを検出するためのものです。MP3、WMA、およびいくつかのグラフィック ファイルの検索を行います。次に、違法な映画を検出したいと考えています。AVI ファイルを開き、詳細を読み取って閉じます。次のコードがあります。

uses WFV; //from JEDI api wrappers

procedure TForm1.Button1Click(Sender: TObject);
var
  lInfo : TAVIFILEINFO      lFile : IAVIFILE;
  lFileType : string;
  lLenMinutes : integer;
  lFPS : integer;
begin
  {init file}
  AVIFileInit;
  {Open file - note: since we search for warez this is perfely "warezy" file}
  AVIFileOpen(lFile, 'e:\Sideways KLAXXON\Sideways KLAXXON.avi', OF_READ, nil);
  {Get file info}
  AVIFileInfoW(lFile, lInfo, sizeof(lInfo));
  lFPS:=Round(lInfo.dwRate /lInfo.dwScale);
  lLenMinutes := Round(lInfo.dwLength  / lFPS / 60);
  lFileType := lInfo.szFileType;
  {just for show: prepare some memo to see what we get}
  memo1.Lines.Clear;

  memo1.Lines.Add('File lenght [min]: ' + IntToStr(lLenMinutes));
  memo1.Lines.Add('Width: ' + IntToStr(lInfo.dwWidth));
  memo1.Lines.Add('Height: ' + IntToStr(lInfo.dwHeight));
  memo1.Lines.Add('File type: ' + lFileType);

  {Closing the file}
  AVIFileRelease (lFile);
  {and here goes the crash}
  FreeAndNil(lFile);

end;

2 つの問題があります。

  1. lLenMinutes は 98 に相当し、映画は約 2 時間です。dwRate は 100 万で、dwScale は 40k であるため、FPS は完全に 25 です。MSDN は次のように述べています。
  2. FreeAndNil 行でコードがクラッシュします。なんで?lFile を解放する責任があると思います (少なくとも、ファイルを解放する必要があると感じています)。FreeAndNil との関係がなければ、プロシージャの終了時に Access Violation が発生します。

では、AVI ファイルから映画の長さを正しく取得する方法を知っていますか? そして、なぜクラッシュしたのですか?

編集

この映画は 2 時間 1 分なので、結果は実際には 120 に近いはずです。lFile は Jedi で次のように宣言されています。

IAVIFile = interface(IUnknown)

AVIFileOpen は JEDI で次のように宣言されています。

function AVIFileOpen(var ppfile: IAVIFILE; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; stdcall; 外部 AVIFILDLL 名 'AVIFileOpenW';

およびMSDNで:

STDAPI AVIFileOpen( PAVIFILE *ppfile, LPCTSTR szFile, UINT モード, CLSID pclsidHandler );

MSDN は次のように述べています。

「AVIFileOpen 関数は AVI ファイルを開き、アクセスに使用されるファイル インターフェイスのアドレスを返します。」

したがって、オブジェクトはこの関数によって作成されると想定しています。

編集 2

mghie がこの質問に回答したため、avi ファイルの長さは新しい質問に移動されました。

4

2 に答える 2

3

機能は対になっていて、一緒AVIFileOpen()AVIFileRelease()属しています。が変数 isAVIFileOpen()と呼ばれる前に、その後 (すべてがうまくいった場合) にはインターフェイス ポインターが含まれます。参照カウントは 1 です。呼び出した後、変数には再び が含まれているはずですが、含まれていません。メソッドがコンパイラ提供のコードを終了してインターフェイス ポインターを解放すると、既に解放されているインターフェイスの参照カウントを減らそうとします。lFilenilAVIFileRelease()nil

これを修正するには、基本的に 2 つの方法があります。

  • の後にインターフェイス ポインターの参照カウントをインクリメントしますAVIFileOpen()

  • 参照カウントを減らそうとせずに変数をリセットします。ポインターへの型キャストを使用します。

    ポインター (lFile) := nil;

AVIFileExit()また、 への呼び出しと一致するように への呼び出しを追加しますAVIFileInit()

于 2009-11-19T20:31:51.673 に答える
1

98 分は 1 時間 38 分です。「約2時間」とは?

FreeAndNil() でのクラッシュに関しては、TObject の子孫を解放し、それを含む変数を nil に設定するように設計されています。コードのどこで TObject の子孫を作成しますか? はインターフェイスのように見えるlFileので、変数を nil に設定するだけで、参照カウントを減らすのに十分なはずです。

lFile := nil;

FreeAndNil() 内の Free への呼び出しが、おそらくクラッシュの原因です。

編集:元の質問の編集に基づいて、明らかに上記は正しくありません。ただし、 への呼び出しAVIFileRelease()によって既にインターフェイスが解放されていると思われるため、何もする必要はありません。lFileとにかく範囲外になり、参照カウントは自動的に減分されます。

に関するMSDNの引用にAVIFileOpen()よると、「ファイルインターフェイスのアドレスを返す」と書かれていることに注意してください。これは COM インターフェースであり、決して DelphiTObjectの子孫ではありません。JEDIコードのスニペットもそう言っていますIAviFileinterface(IUnknown)

于 2009-11-19T19:40:35.380 に答える