0

.NET ( ) のオートメーション API を使用して、自分で生成System.Runtime.InteropServices.ComTypesしたタイプ ライブラリを調べています (Bar.tlb以下を参照)。このタイプ ライブラリは、インポートされたタイプ ライブラリで定義されているインターフェイスIBarを継承するインターフェイスを宣言します。表現を検査すると、例外が発生します。(コードは以下に続きます。)IFooFoo.tlbITypeInfoIBar

コードに入る前に、Bar.tlbタイプ ライブラリを生成する方法を次に示します。

Bar.idl:

[uuid(32E81FDD-BCB0-481B-AD3C-3ED04BFA7D1F)]
library Bar
{
    importlib("Foo.tlb");

    [uuid(CF062BE8-86D2-4D9B-8D1D-D889A77DA876)]
    interface IBar : IFoo { };
}

Foo.idl:

[uuid(22E81FDD-BCB0-481B-AD3C-3ED04BFA7D1E)]
library Foo
{
    importlib("stdole32.tlb");

    [uuid(BF062BE8-86D2-4D9B-8D1D-D889A77DA875)]
    interface IFoo : IUnknown { };
}

次のコマンドを使用して両方の IDL ファイルをコンパイルしましたが、エラーや警告なしで成功しました。

midl.exe /mktyplib203 /env win32 /i … /tlb Foo.tlb Foo.idl
midl.exe /mktyplib203 /env win32 /i … /tlb Bar.tlb Bar.idl

今私がやろうとしていることはこれです:

using System.Runtime.InteropServices;
using ITypeLib = System.Runtime.InteropServices.ComTypes.ITypeLib;
using ITypeInfo = System.Runtime.InteropServices.ComTypes.ITypeInfo;

static class Program
{
    [DllImport("oleaut32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
    static extern ITypeLib LoadTypeLibEx(string path, REGKIND regkind);

    enum REGKIND { REGKIND_NONE = 2 }

    public static void Main()
    {
        ITypeLib typeLib = LoadTypeLibEx(@"C:\Path\To\Bar.tlb", REGKIND.REGKIND_NONE);
        ITypeInfo typeInfo;
        typeLib.GetTypeInfo(0, out typeInfo);
        IntPtr typeAttrPtr;
        typeInfo.GetTypeAttr(out typeAttrPtr); //! COMException: TYPE_E_CANTLOADLIBRARY
        …                                      //                (HRESULT 0x80029c4a)
    }
}

でマークされた行で例外がスローされ//!ます。検査対象ITypeInfoIBarインターフェイス用です。

オートメーション API が継承されたインターフェイスを見つけるのに問題があるに違いないことを理解していますIFoo。これは、登録されていない別のタイプ ライブラリに含まれています。

Bar.tlbしかし、どうやらそれはとにかく検査することが可能であるべきです。OleView.exeうまく管理します:

OleView での <code>Bar.tlb</code> の検査は正常に機能します。

(はい、外部タイプ ライブラリのファイル名を再構築できないという警告が表示されます。これは、 を登録していないためですFoo.tlb。それは私が心配していることではありません。)

OleView.exeクラッシュせずに検査できる場合IBar、コードがクラッシュするのはなぜtypeInfo.GetTypeAttr()ですか? これを修正するにはどうすればよいですか?

4

1 に答える 1

0

TL;DR: Automation API は、参照を解決するために、バックグラウンドで現在の作業ディレクトリにあるタイプ ライブラリにアクセスしているようITypeInfoです。この問題は、次のようにして解決できます。

// using static System.IO.Directory;
SetCurrentDirectory(@"C:\Path\To");
ITypeLib typeLib = LoadTypeLibEx("Bar.tlb", REGKIND.REGKIND_NONE);

それ以外の:

ITypeLib typeLib = LoadTypeLibEx(@"C:\Path\To\Bar.tlb", REGKIND.REGKIND_NONE);

さらに実験を行ったところ、 が同じディレクトリに存在する場合にのみ型の詳細をOleView.exe正常に検査できることがわかりました。別の場所に移動すると、自分のコードと同じように失敗します。IBarBar.tlbFoo.tlbFoo.tlbOleView.exe

<code>Foo.tlb</code> が <code>Bar.tlb</code> から移動されると、<code>OleView.exe</code> で同じ COM エラーが発生します

OleView.exeタイプ ライブラリへのアクセスに使用されるAPI 呼び出しを確認したかったので、以下を確認しました。

dumpbin.exe /imports OleView.exe
dumpbin.exe /exports C:\WINDOWS\…\oleaut32.dll

そして、それが参照していることがわかったLoadTypeLib- ではありませんLoadTypeLibEx。2 つの関数は、タイプ ライブラリの登録方法が異なります。それで、 MSDNのドキュメントLoadTypeLibを調べたところ、次のことがわかりました。

LoadTypeLibタイプ ライブラリのパスが指定されている場合、タイプ ライブラリは登録されません。」

これにより、この回答の冒頭に示されているようにコードを書き直すというアイデアが得られました。

ただし、引用されたテキストが示唆することとは反対に、渡されたパスにディレクトリが存在するかどうかではなく、エラーを解決するLoadTypeLibExのは への呼び出しであることを指摘することが重要です。Directory.SetCurrentDirectory以下も同様に機能します。

// using static System.IO.Directory;
SetCurrentDirectory(@"C:\Path\To");
ITypeLib typeLib = LoadTypeLibEx("C:\Path\To\Bar.tlb", REGKIND.REGKIND_NONE);
于 2016-11-22T22:05:17.303 に答える