我们有一个大型的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中吗?
答案 0 :(得分:22)
似乎stdole.dll是主互操作程序集。见Office 2003 Primary Interop Assemblies on MSDN.
答案 1 :(得分:3)
将旧项目升级到VS 2015是导致stdole.dll在这种情况下开始包含在项目中的原因。
如果库引用在选项中具有“嵌入互操作类型”选项,则首选此选项,之后可能不需要stdole.dll。只需在引用的属性中设置Embed Interop Types=true
即可。
允许此功能的库包括MS Office库,如Office,Excel,Core。一个没有的例子是Crystal Reports。
Hans Passant 强烈反对在此设置Embed Interop Types=false
:What's the difference setting Embed Interop Types true and false in Visual Studio?
答案 2 :(得分:2)
我遇到了同样的问题。我刚从应用程序中删除了引用并重新编译。跑过所有通过的测试。然后在没有dll的情况下重新部署,这一切都有效。
我不知道如何在项目中首先提到这一点。它是一个遗留应用程序,所以必须在很久以前。
西蒙
答案 3 :(得分:0)
我还必须添加对我的stdole项目的引用。即使我没有任何引用它(它是一个简单的图像应用程序),我们的2个用户遇到了它丢失的错误。可能是因为这是3.5应用程序时它们只运行.net 2.0。我弄明白了为什么。
我还在项目属性选项卡上发布,并选择了应用程序文件,然后包含要部署的stdole。希望这会奏效。
答案 4 :(得分:0)
在我们的项目IDispatch中使用stdole.dll。我们将其更改为object并删除IDispatch,然后从引用中删除stole。
答案 5 :(得分:0)
在我的情况下,它是一个旧的未使用的Office Word Interop引用...但删除它是不够的:发布配置文件仍然有行复制stdole.dll!
Query query = FirebaseDatabase.getInstance()
.getReference()
.child("groups").orderByChild("currentMembers").equalTo(currentUserID);
FirebaseRecyclerOptions<UserGroup> options =
new FirebaseRecyclerOptions.Builder<UserGroup>()
.setQuery(query, UserGroup.class)
.build();
删除该行(使用&#39;在文件中查找&#39;)并从远程服务器上的bin文件夹中删除stdole.dll修复了我的问题。
希望这有助于其他人。
答案 6 :(得分:0)
我认为其他任何答案实际上都没有回答“stdole.dll
做什么”的大部分问题。这是我的理解。
此 DLL 位于从托管应用程序最终通向非托管操作系统 DLL 的引用链的顶部,如下所示:
.NET app -->
stdole.dll -->
stdole2.tlb -->
oleaut32.dll
此链中的链接定义明确但模糊不清。这个答案的其余部分走链子......
stdole.dll
本身是一个互操作 DLL。这意味着它是一个 .NET 程序集,其目的本质上是 act as a wrapper 围绕具有 COM 接口的特定非托管类。如果您使用 ILSpy 或 dotPeek 之类的工具查看 stdole.dll
内部,您可以看到里面有什么。这是 StdPicture
接口的 example:
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 可能具有类似的条目)。
这个key有很多有趣的细节,实际上是底层实现的几个版本的细节。例如在子键 2.0\0\win32
下,默认值为:
C:\WINDOWS\SysWow64\stdole2.tlb
对于版本 2 的 32 位变体。这离实际实现 StdPicture
的位置更近了一步。
TLB 文件只是 DLL 的各种 COM“头文件”。它本身没有可执行代码。在像 OLEViewDotNet 或原始 OleView 这样的工具中打开 stdole2.tlb
,您可以读取 typelib 本身的 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 位 StdPicture
库的第 2 版实现了 stdole
coclass。
(虽然我认为这个文件应该在 SysWow64
...?)
如果您要为其他接口遵循此链,您可能最终会使用同一个 DLL 或其他。
请注意,对于某些语言(如 VB6),通常将 TLB 直接嵌入到实现 DLL 中。但这不是 COM 所必需的,而且显然不是微软在这种情况下是如何做到的。