7

CoLoadLibraryとDllGetClassObjectを使用して、DLLを登録せずにIClassFactoryインターフェイスを取得し、COMコンポーネントインターフェイスを取得できることを知っています。

しかし、EXEのCOMコンポーネントはどうでしょうか。別のファイルパスを指定するだけで、EXEタイプのCOMサーバーからCOMコンポーネントインターフェイスを取得する方法はありますか?

4

3 に答える 3

3

実際の 登録なしのCOMを使用する場合は、これをインプロセスとアウトオブプロセスの両方のCOMオブジェクトで機能させることができるはずです。

Sharptoothが指摘したように、あなたは実際には登録なしのCOMを使用していません。代わりに、COMがアクティベーション中に使用する呼び出しを偽造することで、実際に自分自身をローリングしています。アプリケーションとアクティブ化するCOMサーバーの両方を制御する場合、ソリューションは機能しますが、そうでない場合は失敗する可能性があります。

于 2010-07-10T04:20:11.913 に答える
2

いいえ、あなたがすることはできません。プログラムとout-procCOMサーバー間でCOMセットアップマーシャリングが必要です。これを実現するには、を呼び出してから、またはCoInitialize()のいずれかCoCreateInstance()を呼び出す必要がありますCoGetClassObject()

インプロセスサーバーで記述したパス(呼び出しCoLoadLibrary()てから呼び出しDllGetClassObject())は、実際にはダーティハックです。通常のCOMメカニズムをバイパスするため、たとえば、スレッドモデル要件(STA / MTA)を満たす必要がある場合でも、マーシャリングは開始されません。もの)。インプロセスサーバーは、いくつかのよく知られた関数が公開された通常のDLLであるため、このようなダーティハックが発生する可能性があります。アウトプロセスCOMサーバーでも同じことは不可能です。その場合はCOMに依存する必要があります。

于 2010-07-09T09:47:49.157 に答える
1

COMコンポーネントは、関数呼び出しでポインターとして渡すことができます。

したがって、EXEにオブジェクトを実装し、DLLから別のCOMオブジェクトをロードすると、EXEベースのオブジェクトをDLLからオブジェクトに渡すことができます。ロードされたオブジェクトは、ポインタを受け入れる関数を持つインターフェイスをサポートする必要があります。

interface ILoadedObject
{
    HRESULT GiveObject(IUnknown *pObj);
};

DLLベースのオブジェクトがそれを実装している場合は、EXEから呼び出して、どこにも登録されていないオブジェクトを渡すことができるため、これを実現するためにEXEにオブジェクトを登録する必要はありません。

唯一の要件は、次の正しい実装にあります。適切な回数呼び出されるIUnknownまでオブジェクトを破棄しないでください。また、オブジェクトの固定されたインターフェイスセット間を移動するために使用できることと、クエリを実行すると常に同じアドレス。ReleaseQueryInterfaceIUnknown

一方、EXEをオブジェクトのサーバーとして登録することはできますが、それは非常に複雑になります。COMは、EXEの実行を開始してから、Windowsメッセージキューを介してメッセージを送信する必要があります。これは、OLEにのみ広く使用されています。非常に壊れやすい場合があります。

アップデート

より完全な解決策は、オブジェクトタイプのインスタンスを作成する標準的な方法を定義することですが、EXEがその動作を定義できるようにすることです。EXEは以下を実装します:

interface IComponent;

interface IEnvironment : IUnknown
{
    HRESULT CreateInstance(REFCLSID clsid, IComponent **ppNew);
}

すべてのコンポーネントは、このインターフェースをサポートする必要があります。

interface IComponent : IUnknown
{
    HRESULT SetEnvironment(IEnvironment *pEnv);
}

ここで、EXEがレジストリを使用してコンポーネントを検索する標準の動作を取得するために、次のCreateInstanceようなメソッドを実装できます。

HRESULT Env::CreateInstance(REFCLSID clsid, IComponent **ppNew)
{
    HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
                     __uuidof(IComponent), (void **)&ppNew);
    if (FAILED(hr))
        return hr;

    (*ppNew)->SetEnvironment(this);
    return S_OK;
}

しかしもちろん、これを変更して、いくつかのコンポーネントを「注入」することができます。したがって、レジストリの代わりに(またはレジストリに加えて)、構成ファイルを使用できます。または(あなたが尋ねたように)EXEにはいくつかのコンポーネントの実装が組み込まれている可能性があります:

すべてのコンポーネントは、作成時に環境が通知されるため、環境を使用してさらにコンポーネントを作成できます。

// inside some component:
HRESULT Comp::SetEnvironment(IEnvironment *e)
{
    m_env = e; // using a smart pointer for ref-counting
    return S_OK;
}

// in some method of the component

ComPtr<IComponent> button;
m_env->CreateInstance(CLSID_Button, &button);

// now query button for more useful interface...

したがって、コンポーネントが作成されるたびに、環境(EXEで定義)は、コンポーネントの実装がどのように検出されるかを正確に制御できます。すべての作成はEXEを介して行われます。

これは、「依存性注入」または「制御の反転」と呼ばれることもあります。

于 2010-07-09T09:29:32.273 に答える