stdole.dll做什么用?

39 c# com stdole

我们有一个大型的C#(.net 2.0)应用程序,它使用我们自己的C++ COM组件和第三方指纹扫描程序库,也可以通过COM访问.我们遇到了一个问题,在生产过程中,指纹库中的某些事件不会被C#应用程序触发,尽管来自我们自己的C++ COM组件的事件被触发并且收到的很好.

使用MSINFO32将工作系统上加载的模块与发生故障的系统上的模块进行比较,我们确定这是由STDOLE.DLL不在GAC中引起的,因此未加载到故障进程中.

将此文件拖到GAC中会导致事件从指纹COM库恢复正常.

那么stdole.dll做什么?它的大小是16k所以它不能太多......它是否与STDOLE32这样的另一个库有某种联系?它的缺席怎么会导致这种奇怪的行为?

我们如何分发stdole.dll?这是一个XCOPY部署应用程序,我们不使用GAC.我们应该将它打包为资源并使用System.EnterpriseServices.Internal.Publish.GacInstall来确保它在GAC中吗?

art*_*r02 22

似乎stdole.dll是主要的互操作程序集.请参阅MSDN上的Office 2003主互操作程序集.

  • 它可以使用像IFont或IDispatch这样的"标准"COM接口.似乎支持.NET中的这些接口需要ref stdole.dll.我很困惑为什么这个程序集与Office绑在一起. (2认同)

Ton*_* L. 5

这里也讨论了这个问题:Why is Visual Studio 2015 add stdole.dll and Microsoft.AnalysisServices.AdomdClient.dll to my project?

在这种情况下,将旧项目升级到 VS 2015 是导致 stdole.dll 开始包含在项目中的原因。

如果库引用在属性中具有“嵌入互操作类型”选项,则这是首选选项,此后可能不需要 stdole.dll。Embed Interop Types=true只需在参考的属性中设置即可。

允许这样做的库包括 MS Office 库,例如 Office、Excel、Core。Crystal Reports 就是一个不具备这种功能的例子。

Hans Passant 强烈建议不要在此处进行设置Embed Interop Types=falseWhat's the Difference set Embed Interop Types true and false in Visual Studio?


Dav*_*Caz 5

我认为其他任何答案都没有真正回答大部分“做什么stdole.dll”的问题。这是我的理解。

概括:

该 DLL 位于从托管应用程序最终指向非托管操作系统 DLL 的引用链的顶部附近,如下所示:

    .NET app -->
        stdole.dll -->
            stdole2.tlb -->
                oleaut32.dll
Run Code Online (Sandbox Code Playgroud)

这条链条中的链接定义明确但模糊。这个答案的其余部分沿着链条走……


详细解释:

stdole.dll它本身是一个互操作DLL。这意味着它是一个 .NET 程序集,其目的本质上是充当具有 COM 接口的特定非托管类的包装器。如果您使用ILSpystdole.dll或 dotPeek等工具查看内部,您可以看到里面有什么。以下是该界面的示例StdPicture

using System.Runtime.InteropServices;

namespace stdole
{
  [CoClass(typeof (StdPictureClass))]
  [Guid("7BF80981-BF32-101A-8BBB-00AA00300CAB")]
  [ComImport]
  public interface StdPicture : Picture
  {
  }
}
Run Code Online (Sandbox Code Playgroud)

所有这些都是一个带有属性的接口,这些属性对真正应该使用的 COM 类的详细信息进行编码。像这样的 DLL 通常是使用类似工具自动创建的,tlbimp.exe或者当您将非托管 COM DLL 直接添加到项目中作为引用时,Visual Studio 会为您执行此操作。


我们可以再深入一点。Guid上面示例中的A7BF80981-BF32-101A-8BBB-00AA00300CAB通常可以在 Windows 注册表中找到,当实际从托管代码中使用它时,运行时将在其中查找stole.StdPicture

如果您使用 RegEdit 搜索该 GUID,您会发现:

using System.Runtime.InteropServices;

namespace stdole
{
  [CoClass(typeof (StdPictureClass))]
  [Guid("7BF80981-BF32-101A-8BBB-00AA00300CAB")]
  [ComImport]
  public interface StdPicture : Picture
  {
  }
}
Run Code Online (Sandbox Code Playgroud)

其中具有价值 00020430-0000-0000-C000-000000000046

搜索该值,您会发现:

Computer\HKEY_CLASSES_ROOT\Interface\{7BF80981-BF32-101A-8BBB-00AA00300CAB}\TypeLib
Run Code Online (Sandbox Code Playgroud)

(同一 DLL 中的大多数其他 GUID 可能有类似的条目)。

这个密钥有很多有趣的细节,实际上是底层实现的几个版本的细节。例如,在子项下, 2.0\0\win32 默认值为:

Computer\HKEY_CLASSES_ROOT\TypeLib\{00020430-0000-0000-C000-000000000046}
Run Code Online (Sandbox Code Playgroud)

StdPicture对于版本 2 的 32 位变体。这离实际实现更近了一步。


TLB 文件只是 DLL 的一种 COM“标头”。它本身没有可执行代码。在OLEViewDotNet或原始OleView 等stdole2.tlb工具中打开,您可以读取类型库本身的 IDL。在这种情况下,第一部分具有以下内容:

// typelib filename: stdole2.tlb

[
  uuid(00020430-0000-0000-C000-000000000046),
  version(2.0),
  helpstring("OLE Automation")
]
library stdole
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,它uuid与我们从上面的 Regedit 获得的值相同。向下滚动最终我们来到StdPicture条目,与上面的示例相同:

[
  uuid(0BE35204-8F91-11CE-9DE3-00AA004BB851)
]
coclass StdPicture {
    ...
};
Run Code Online (Sandbox Code Playgroud)

同样,这里没有真正的代码,只有一个类定义。回到RegEdit我们可以发现uuid

Computer\HKEY_CLASSES_ROOT\CLSID\{0BE35204-8F91-11CE-9DE3-00AA004BB851}\InprocServer32
Run Code Online (Sandbox Code Playgroud)

其值为C:\Windows\System32\oleaut32.dll. 现在我们知道这个 DLL 实现了StdPicture32 位库版本 2 的组件类stdole

(虽然我认为这个文件应该在SysWow64......?)

如果您要遵循此链来获取其他接口,则可能会得到相同的 DLL 或另一个。

请注意,对于某些语言(如 VB6),TLB 通常直接嵌入到实现 DLL 中。但这对于 COM 来说不是必需的,而且显然 Microsoft 在本例中也不是这样做的。