stdole.dll是什么作用?

47
我们有一个大型的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中吗?
7个回答

25

是的,我也在 PIA 目录中找到了一份副本。我们的应用程序不使用 Office 组件;而且这仍然无法解释我们所看到的行为! - rc1
2
它可能会使用像IFont或IDispatch这样的“标准”COM接口。似乎.NET中对这些接口的支持需要引用stdole.dll。我困惑为什么这个程序集与Office相关联。 - Aardvark

5

我认为其他回答并没有回答问题“stdole.dll的作用”大部分内容。以下是我的理解。

概述:

这个DLL位于一个引用链的顶部,从您的托管应用程序最终引用到非托管操作系统DLL,它看起来像这样:

    .NET app -->
        stdole.dll -->
            stdole2.tlb -->
                oleaut32.dll

这个链中的链接很清晰,但却不太明显。本回答的其余部分将逐步解释这个链...

详细解释:

stdole.dll 本身是一个交互 DLL。这意味着它是一个 .NET 组件,其目的实质上是充当包装器,围绕具有 COM 接口的特定非托管类。如果您使用像 ILSpy 或 dotPeek 这样的工具查看 stdole.dll,您可以看到其中的内容。以下是 StdPicture 接口的 示例

using System.Runtime.InteropServices;

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

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


我们可以深入了解一下。在上面的示例中,Guid(全局唯一标识符)7BF80981-BF32-101A-8BBB-00AA00300CAB 通常会在 Windows 注册表中找到,这就是运行时从托管代码实际使用 stole.StdPicture 时要查找的地方。
如果您使用 RegEdit 搜索该 GUID,则会找到:
Computer\HKEY_CLASSES_ROOT\Interface\{7BF80981-BF32-101A-8BBB-00AA00300CAB}\TypeLib

该值为00020430-0000-0000-C000-000000000046

搜索该值,您将找到:

Computer\HKEY_CLASSES_ROOT\TypeLib\{00020430-0000-0000-C000-000000000046}

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

实际上,此键具有许多有趣的细节,事实上是底层实现的几个版本的细节。例如,在子键 2.0\0\win32 下,默认值为:

C:\WINDOWS\SysWow64\stdole2.tlb

对于版本2的32位变体来说,这是更接近实际实现StdPicture的一步。


一个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
{
    ...
}

请注意,uuid 的值与我们在上面从 Regedit 中获取的值相同。向下滚动,我们最终会来到 StdPicture 条目,这与上面的示例相同:
[
  uuid(0BE35204-8F91-11CE-9DE3-00AA004BB851)
]
coclass StdPicture {
    ...
};

再次提醒,这里没有真正的代码,只有一个类定义。回到RegEdit,我们可以找到uuid
Computer\HKEY_CLASSES_ROOT\CLSID\{0BE35204-8F91-11CE-9DE3-00AA004BB851}\InprocServer32

其值为C:\Windows\System32\oleaut32.dll,我们现在知道此DLL实现了32位stdole库版本2的StdPicture coclass。

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

如果您要遵循某些其他接口的链,则可能会到达相同的DLL或另一个DLL。

请注意,对于某些语言(如VB6),将TLB嵌入实现DLL直接中是很典型的。但这不是COM所必需的,显然也不是Microsoft在此情况下的做法。


5

这个问题也在这里进行了讨论:为什么Visual Studio 2015会将stdole.dll和Microsoft.AnalysisServices.AdomdClient.dll添加到我的项目中?

将老项目升级到VS 2015导致stdole.dll开始被包含在项目中。

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

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

Hans Passant强烈反对在此处设置Embed Interop Types=false: 在Visual Studio中设置Interop Types为true和false有什么区别?


3

我曾经遇到过同样的问题。我只是从应用程序中删除了参考并重新编译了一次。运行了所有测试,测试都通过了。然后在没有dll文件的情况下重新部署,一切都正常了。

我不知道这个项目最初是如何引用这个dll的。这是一个旧的应用程序,所以可能是很久以前的事了。

Simon


2
在我的情况下,这是一个旧的未使用的Office Word Interop引用...但仅仅删除它是不够的:发布配置文件仍然有复制stdole.dll的行!
<File Include="bin/stdole.dll"> ...

删除使用“在文件中查找”找到的那行代码,并且从远程服务器的bin文件夹中删除stdole.dll,这样就解决了我的问题。

希望这能帮助其他人。


0
在我们的项目中,使用了stdole.dll来进行IDispatch课程。我们将其更改为对象并删除了IDispatch,然后从引用中删除了stdole。

0

我还不得不为stdole添加一个项目引用。尽管我没有任何对它的引用(这是一个简单的图像应用程序),但我们的两个用户却收到了缺失错误。可能是因为他们只运行.net 2.0,而这是一个3.5应用程序。我已经找出原因。

我还进入了项目属性选项卡上的发布,并选择了应用程序文件,然后包括stdole以进行部署。希望这样能够解决问题。


2
可能会起作用,但stdole.dll不是可再分发的文件,根据此文档(搜索stdole)http://msdn.microsoft.com/en-us/library/aa195478(office.11).aspx,它可能会破坏现有的安装。 - Ed Guiness

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接