ホーム >プログラム >Delphi 6 ローテクTips >MSWebDVDでDVD再生その1

TMSWebDVDでDVDプレーヤーソフトを作ろうというページ。



まずはデコーダとTMSWebDVDの取り込みから
Windows XPにはDVDを再生させるためデコーダが標準でインストールされていません。
そのままではDVDは再生できないということです。
またMSWebDVDもデコーダを内臓しているわけではないので、結局DVDを再生させるには事前にPowerDVDやWinDVDなど市販のDVDプレーヤーをインストールする必要があります。
TMSWebDVDをコンポーネントとして取り込むには、Delphiのメニューで「コンポーネント」→「ActiveX コントロールの取り込み」と選んで出てきたダイアログのリストから選択します。

「TMSWebDVDとTMSDVDAdmの二つのコンポーネントがあります。
このうちTMSDVDAdmはあまり再生には関係してきません。
主にDVDの設定をレジストリへ保存したりレジストリから読み出すのに使うようです。

インストールは「新規パッケージに追加」を選びます。
「既存のパッケージへ追加」でもよいのですが、単独のパッケージにした方が後々面倒がなくて良いかなと。
多分ソースコードを書き換えてコンパイルし直さないといけなくなると思うので。

インストールするとActiveXのパレットに「DVD」のアイコンのコンポーネントが二つ追加されます。

フォームに貼り付けるとこんな感じ。
TWindowsMediaPlayerと違って再生ボタンやシークバーなどのコントロール類は一切ありません。
全部自前で用意しないとなりません。

再生

TMSWebDVDをフォームに貼り付けると、DVDプレーヤーを読みにいきDVDDirectoryプロパティの値を自動でセットしてくれます。
ということで再生させるにはPlayメソッドを呼ぶだけでOKです。

procedure TForm1.FormCreate(Sender: TObject);
begin
  MSWebDVD1.Align := alClient;
  Show;
  MSWebDVD1.Play;
end;

これで再生が始まります。
注意する点はフォームを表示させてからPlayを呼ぶことです。
表示する前にPlayを呼ぶと「この操作を完了するのに必要なデータは、まだ利用できません。」というエラーが出ます。

Alignをセットするのはフォームを表示する前に済ませた方が良いようです。
表示した後だとうまくいかない場合もあるようなので。

ちなみにプログラムを続けていると「インターフェースがサポートされていません」というエラーメッセージが出て再生できなくなることがあります。
その場合Delphiを一旦終了させると改善します。
だめな場合でも再起動すれば直ると思います。
procedure TForm1.FormDestroy(Sender: TObject);
begin
  try
    MSWebDVD1.Stop;
  except end;
end;
念のため終了時にはStopさせておきます。
これをしなくても問題はないようですが、この処理を入れたら再生のエラーが出なくなったこともあったので。
DVDNotifyイベント
DVDの再生でタイトル再生が始まったりメニューが選択されたりしたというようなイベントを取得するにはDVDNotifyイベントを使います。
が、これを指定するとエラーが出ます。
手がつけられないほど出ます。
//DVDNotifyイベント
procedure TForm1.MSWebDVD1DVDNotify(Sender: TObject; lEventCode: Integer; lParam1, lParam2: OleVariant);
begin
  //とりあえずなにもしない
end;
この状態で出てしまいます。
こちらのプログラムミスとかそういうレベルのことではないようです。

このようなエラーが立て続けに50個近く出ます。
Read of address の後の数値は 00000000 の場合もあれば 00000002 もあったり色々です。

イベントを解除すれば正常に動きます。

システムがおかしくなったのかとも思いC#で同じように作ってみたところ、そちらは問題なく動作しました。
ということでDelphi固有の問題であろうと判断。

OnDVDNotifyイベントの引数を見てみると、IntegerとOleVariantがあります。
とりあえずIntegerは問題なかろうということで、lParam1, lParam2のOleVariantを疑ってみました。
とはいえOleVariantというのが一体何なのか良く分かっていないので手探りの状態なのですが。
マイクロソフトのページでNotifyイベントを調べてみると、lParam1, lParam2に渡されるのは大体DWORDやULONGだったりします。
ならばいっそOleVariantではなくIntegerでいいのではないか?と、だめもとでIntegerに書き換えてコンポーネントを再コンパイルしてみました。

取り込んだ MSWEBDVDLib_TLB.pas を直接書き換えます。
結構勇気がいります。

// *********************************************************************//
// OLE Control Proxy class declaration
// Control Name : TMSWebDVD
// Help String : MSWebDVD Class
// Default Interface: IMSWebDVD
// Def. Intf. DISP? : No
// Event Interface: _IMSWebDVD
// TypeFlags : (2) CanCreate
// *********************************************************************//

  TMSWebDVDDVDNotify = procedure(Sender: TObject; lEventCode: Integer; lParam1: OleVariant;
                                                    lParam2: OleVariant) of object;
  TMSWebDVDPlayForwards = procedure(Sender: TObject; bEnabled: WordBool) of object;
  TMSWebDVDPlayBackwards = procedure(Sender: TObject; bEnabled: WordBool) of object;
677〜8行にある文を書き換えます。
// *********************************************************************//
// OLE Control Proxy class declaration
// Control Name : TMSWebDVD
// Help String : MSWebDVD Class
// Default Interface: IMSWebDVD
// Def. Intf. DISP? : No
// Event Interface: _IMSWebDVD
// TypeFlags : (2) CanCreate
// *********************************************************************//

//  TMSWebDVDDVDNotify = procedure(Sender: TObject; lEventCode: Integer; lParam1: OleVariant;
//                                                    lParam2: OleVariant) of object;

  TMSWebDVDDVDNotify = procedure(Sender: TObject; lEventCode: Integer; lParam1, lParam2: Integer) of object;

  TMSWebDVDPlayForwards = procedure(Sender: TObject; bEnabled: WordBool) of object;
  TMSWebDVDPlayBackwards = procedure(Sender: TObject; bEnabled: WordBool) of object;
そしてプログラムもコンパイル。起動。
エラーは出ません。
lParam1、lParam2の値も期待通りのものが得られます。
じゃぁ、これでいいのかなぁと。
でも、Integerでいいわけないよねぇと。

で、OleVariantの定義を見てみようとしたらPOleVariantというのがありました。
これか?と。
先ほどのlParam1、lParam2の型をIntegerからPOleVariantに書き換え。
// *********************************************************************//
// OLE Control Proxy class declaration
// Control Name : TMSWebDVD
// Help String : MSWebDVD Class
// Default Interface: IMSWebDVD
// Def. Intf. DISP? : No
// Event Interface: _IMSWebDVD
// TypeFlags : (2) CanCreate
// *********************************************************************//

//  TMSWebDVDDVDNotify = procedure(Sender: TObject; lEventCode: Integer; lParam1: OleVariant;
//                                                    lParam2: OleVariant) of object;

  TMSWebDVDDVDNotify = procedure(Sender: TObject; lEventCode: Integer; lParam1, lParam2: POleVariant) of object;

  TMSWebDVDPlayForwards = procedure(Sender: TObject; bEnabled: WordBool) of object;
  TMSWebDVDPlayBackwards = procedure(Sender: TObject; bEnabled: WordBool) of object;
再びコンポーネントを再コンパイル
そしてプログラムもコンパイル。起動。
エラーは出ません。
値を得るにはDWORDやULONGなどでlParam1やlParam2をキャストしなければなりませんが、期待通りの値は得られます。
これで本当にいいのかどうか自信はまったくありませんが、少なくともIntegerに書き換えるよりはましなんじゃなかろうかなぁと。

で、エラーが出ていたときのRead of address の後の数値を見てみると、取り出したかった値と同じようなのです。
つまりOleVariantの場合は本来0や2という値を返すはずが、それをアドレスとみなしてしまうのでアクセス違反を起こしてエラーを出していたのではなかろうかと。

なんにせよこれで無事Notifyイベントを取得することができるようになりました。

その2へ


2009-03-01