我正在使用.NET中的Automation API(System.Runtime.InteropServices.ComTypes
)来检查我自己生成的类型库Bar.tlb
(见下文)。此类型库声明了一个接口IBar
,它继承自接口IFoo
,该接口在导入的类型库Foo.tlb
中定义。检查代表ITypeInfo
的{{1}}会导致异常。 (代码如下。)
在我开始使用代码之前,我的方法是如何生成IBar
类型的库。
Bar.tlb
[uuid(32E81FDD-BCB0-481B-AD3C-3ED04BFA7D1F)]
library Bar
{
importlib("Foo.tlb");
[uuid(CF062BE8-86D2-4D9B-8D1D-D889A77DA876)]
interface IBar : IFoo { };
}
我使用以下命令编译了两个IDL文件,这些命令成功,没有任何错误或警告:
[uuid(22E81FDD-BCB0-481B-AD3C-3ED04BFA7D1E)]
library Foo
{
importlib("stdole32.tlb");
[uuid(BF062BE8-86D2-4D9B-8D1D-D889A77DA875)]
interface IFoo : IUnknown { };
}
现在我要做的是:
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)
}
}
的行上抛出异常。已检查的//!
是ITypeInfo
界面的一个。
据我所知,Automation API必须在找到继承的接口IBar
时遇到问题,该接口包含在另一个未注册的类型库中。
但显然无论如何都应该可以检查IFoo
。 Bar.tlb
管理得很好:
(是的,它会发出警告,说明无法重建外部类型库的文件名,这是因为我没有注册OleView.exe
。这不是我担心的问题。)
如果Foo.tlb
能够在不崩溃的情况下检查OleView.exe
,为什么我的代码会因为IBar
这么简单而崩溃?我该如何解决这个问题?
答案 0 :(得分: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
存在于同一目录中,IBar
只能成功检查Bar.tlb
中的Foo.tlb
类型详细信息。一旦我将Foo.tlb
移到其他地方,OleView.exe
就像我自己的代码一样失败了:
我想看看用于访问类型库的API调用OleView.exe
,所以我查了一下:
dumpbin.exe /imports OleView.exe
dumpbin.exe /exports C:\WINDOWS\…\oleaut32.dll
并发现它引用了LoadTypeLib
- 而不是LoadTypeLibEx
。这两个函数的类型库注册方式不同。所以我查了MSDN documentation for LoadTypeLib
并发现了这个:
如果指定了类型库的路径,“
LoadTypeLib
将不会注册类型库。”
这让我有了重写代码的想法,如本答案开头所示。
然而,重要的是要指出,与引用文本所暗示的相反,传递给LoadTypeLibEx
的路径中是否存在目录 - 这是对{{1}的调用这解决了错误。以下也适用:
Directory.SetCurrentDirectory