2

アプリケーションで GRF ファイルから Directshow IFilterGraphs をロードすると、DLL にグローバルに登録されている通常のフィルターに対して正常に機能します。

    // open structured storage file...
    hr = pStorage->OpenStream(L"ActiveMovieGraph", 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
if (SUCCEEDED(hr)) {
    hr = pPersistStream->Load(pStream);
    pStream->Release();
}

ただし、一部のフィルターは、IClassFactory 実装から呼び出される CoRegisterObject を使用して EXE にローカルに登録されます。これらのフィルターは、IClassFactory 実装が IClassFactory::CreateInstance 呼び出しを受け取ると、C++ new で作成されます。

    HRESULT hr = CoRegisterClassObject(*m_pTemplate->m_ClsID, this, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &m_RegisterKey);

ローカル フィルターは、CoCreateInstance を介して直接作成された場合に正常に機能します。C++ new で直接作成した場合も問題なく動作します。

CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&instance);

これらのローカル フィルターを含む GRF ファイルの読み込みは機能せず、HRESULT 0x80040154 Class not registered from IPersistStream::Load を返します。

アプリケーションの IClassFactory::CreateInstance 関数は呼び出されませんが、CoCreateInstance API は IPersistStream::Load 中に正しい CLSID で呼び出されますが、IPersistStream::Load 呼び出しとは別のスレッドから呼び出されます (COM アパートメント スレッドで初期化されたメイン アプリケーション スレッド上)。 )。もう 1 つの違いは、IPersistStream::Load から呼び出されたときの dwContext が CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER であることです。ただし、メイン スレッドからの CoCreateInstance 呼び出しは、この dwContext 値で引き続き機能します。CLSCTX_INPROC_HANDLER フラグを含む CoRegisterClassObject 呼び出しは、E_INVALIDARG で失敗します。

ole32.dll!CoCreateInstance(const _GUID & rclsid, IUnknown * pUnkOuter, unsigned long dwContext, const _GUID & riid, void * * ppv)  Line 96  C++
quartz.dll!_CoCreateFilter@8()  + 0x1a bytes    
quartz.dll!CFilterGraph::OnCreateFilter()  + 0x55 bytes 
quartz.dll!CFGControl::CGraphWindow::OnReceiveMessage()  + 0x2d05 bytes 
quartz.dll!WndProc()  + 0x3e bytes  
user32.dll!_InternalCallWinProc@20()  + 0x23 bytes  
user32.dll!_UserCallWinProcCheckWow@32()  + 0xb7 bytes  
user32.dll!_DispatchMessageWorker@8()  + 0xed bytes 
user32.dll!_DispatchMessageW@4()  + 0xf bytes   
quartz.dll!ObjectThread()  + 0x65 bytes 
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes    
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes   
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes    

rclsid  {CA6B3460-28B3-4A6E-A7FC-A83CF1DEEC49}  const _GUID &
pUnkOuter   0x00000000  IUnknown *
dwContext   3   unsigned long
riid    {IID_IBaseFilter}   const _GUID &

アプリケーションは、MFC アプリケーションの推奨事項として CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) を呼び出します。CoRegisterClassObject の呼び出しで異なるコンテキストとフラグの値を使用しようとしましたが、成功しませんでした。GRF ファイルには、プロセス ローカル フィルターの正しい CLSID が確実に含まれています。

この動作は、アプリケーションの Win32 および x64 ビルドと同じです。ホスト OS は Windows 7 x64 です。

IFilterGraph シリアル化は、CoRegisterClassObject に登録されたプロセス ローカル フィルターをサポートしていますか? もしそうなら、アプリケーションの動作に問題がありますか? この問題をさらに診断するために実行できる手順はありますか?

4

2 に答える 2

2

.GRFファイル ストーリー全体が本番環境で使用されることは想定されていません。これは、デバッグ、開発、トラブルシューティングに役立つオプションです。そして、ここで、そもそも使用目的が限られているため、ドキュメントで十分に説明されていない制限の 1 つにぶつかっています。

フィルター グラフは、フィルターが DLL (Bothアパートメント モデルでマークされたクラス)によってホストされることを想定しているため、表示されCoCreateInstanceている引数を使用して呼び出しを発行します。CLSID_FilterGraphさらに、フィルター グラフを使用している場合は、MSDN が言うように、次のようになります。

共有ワーカー スレッドでフィルター グラフ マネージャーを作成します。

そして、予期しないスレッドでのインスタンス化呼び出しが表示されます。

合理的な努力をすれば、まだ機能させることができると思います。まず、CLSID_FilterGraphNoThread代わりにスレッド化の問題を解決し、インスタンス化呼び出しを、呼び出しで既に準備したアパートメント内の呼び出しスレッドで発生させる必要がありますCoRegisterClassObject

スレッドの問題が解決されれば、問題にはCLSCTXなりません。CLSCTX_INPROC_SERVER呼び出しでコンテキスト フラグを選択してCoRegisterClassObjectいるので、COM コンテキストを準備し、クラス ファクトリを .GRF ロード内部から呼び出すだけで十分です。

UI スレッドからグラフを作成している場合、または通常の操作の一部としてメッセージ ループを持つスレッドを作成している場合は、通常とCLSID_FilterGraphNoThread同じように機能するはずCLSID_FilterGraphです。CLSID_FilterGraphNoThreadは基本的にまれな鳥ですが、Windows Media Player は内部的にそれを使用しており、おそらくそれがフィルタ グラフ クラスのこのバリアントが存在する理由です。

于 2013-02-17T19:46:17.760 に答える
1

将来の読者のために、これで問題が解決しました。

CoCreateInstance がローカル COM オブジェクトを処理するすべてのアパートメントから CoRegisterClassObject を呼び出します。

CLSID_FilterGraph を使用して GRF ファイルをロードし、ローカルに登録されたフィルターをインスタンス化することは、アプリケーション内のいずれかの MTA スレッドから CoRegisterClassObject を呼び出し、少なくとも 1 つの MTA スレッドが常に実行されていることを確認することも意味します。

STA アプリケーションでこれを行う最も簡単な方法は (無駄かもしれませんが)、CoInitializeEx(NULL, COINIT_MULTITHREADED) を呼び出してから CoRegisterClassObject を呼び出してからスリープし、決して終了しないスレッドを開始することです。

COM スレッド モデルの理解と使用には、COM アパートメントに関する MSDN の役立つ説明があります。

于 2013-03-08T11:38:51.107 に答える