我们有一个大型的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主互操作程序集.
在这种情况下,将旧项目升级到 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 set Embed Interop Types true and false in Visual Studio?
我认为其他任何答案都没有真正回答大部分“做什么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 在本例中也不是这样做的。
| 归档时间: |
|
| 查看次数: |
59166 次 |
| 最近记录: |