
Does Vista do stricter checking of Interface Ids in DCOM calls? (the Stub received bad Data)?我希望每个人都可以原谅这个问题的长度和叙述方式。我决定在我的博客中详细描述这种情况。后来我看到乔尔(Joel)的邀请访问此站点,我想将其粘贴到此处以查看是否有人对此情况有任何了解。 我编写并现在支持一个应用程序,该应用程序由一个Visual Basic胖客户端组成,该客户端将DCOM与使用ATL用C编写的中间层COM组件进行对话。它在我们所有的八个办公室中运行。每个办公室都托管一个后端服务器,该服务器包含COM应用程序(由18个独立的组件组成)和SQLServer。 SQLServer通常位于同一后端服务器上,但不必位于同一后端服务器上。 我们最近将纽约最大的办公室中的后端服务器从MSC群集迁移到了基于VMWare的ESX技术托管的新虚拟机。由于COM应用程序的位置已从旧服务器移到了另一个具有不同名称的服务器,因此我不得不重定向所有客户端,以便它们在新服务器上激活COM应用程序。该过程有些陈旧,因为我对经历了类似基础架构升级的几个小型办公室进行了基本上相同的操作。 一切似乎都很常规,在星期一早上,整个办公室(约1000个Windows XP工作站)都在新服务器上正常运行。但是后来打来的电话来自我的移动小组-一位律师在家中使用VPN连接,在重定向到新服务器后出现一个奇怪的错误:
嗯?我以前从未见过此错误消息。是新服务器吗?但是办公室的所有工作站都工作正常。我告诉移动小组将律师切换回旧服务器(仍在工作),错误消失了。那有什么区别呢?原来这名律师在家中运行Vista。 我们在任何办公室中都没有运行Vista,但确实有一些律师在家中运行Vista(某些在我的纽约办公室中)。我也这样做,但是我从未见过这个问题。为了确认是否存在问题,我启动了Vista笔记本电脑,将其指向新服务器,并得到了相同的错误。我将其指向旧服务器,并且工作正常。显然,Vista和新服务器上的组件存在一些问题-该问题似乎并未影响XP客户端。可能是什么? 下一站-我的笔记本电脑上出现应用程序错误日志。这产生了有关错误的更多信息:
接口ID提供了我解开谜团所需的线索。"预期的"接口ID标识MDAC的Recordset接口-特别是该接口的2.1版。"返回"接口对应于Recordset的更高版本(版本2.5与版本2.1有所不同,因为它在vtable的末尾添加了一个附加条目-方法Save)。 实际上,我组件的接口公开了许多将Recordset作为输出参数传递的方法。那么,他们是否突然返回具有不同接口ID的Recordset的更高版本?看来确实是这样。然后我想,为什么要重要。对于较旧界面的客户端,vtable看起来相同。的确,我怀疑如果我们谈论的是进程内COM,而不是DCOM,那么显然这种无害的阻抗失配将被默默忽略,并且不会造成任何问题。 当然,当进程和机器的边界发挥作用时,客户端和服务器之间就会有一个代理和一个存根。在这种情况下,我使用了带有自由线程编组器的类型库编组。因此,有两个谜题需要解决: 为什么我的新服务器上的方法的输出参数中返回的接口不同? 为什么这只会影响Vista客户端? 由于我的服务器软件托管在我八个办公室中每个办公室的服务器上,因此我决定尝试依次将我的Vista客户端指向所有这些办公室,以查看哪些问题出在Vista上,哪些问题出在Vista上。照明测试。某些较旧的服务器仍可与Vista一起使用,但较新的服务器则无法。尽管一些较旧的服务器仍在运行Windows 2000,而较新的服务器在2003年运行,但这似乎不是问题所在。 在比较了组件DLL的日期之后,似乎每当客户端指向带有日期为2003 Vista之前的组件DLL的服务器时,就可以了。但是那些带有DLLs的日期在2003年之后的对象是有问题的。信不信由你,多年来,服务器组件上的代码都没有(或至少没有重大变化)。显然,日期不同仅是由于我在开发机器上重新编译了组件。看来其中一次重新编译发生在2003年。 灯泡亮了。当将记录集从服务器传递回客户端时,我的ATL C组件将接口称为_Recordset。此符号来自msado15.dll中嵌入的类型库。这是我在C代码中得到的行:
不要被msdad15.dll中的15所欺骗。显然,此DLL在较长的MDAC版本中并未更改名称。 当我回头编译应用程序时,MDAC的版本为2.1。因此_Recordset使用2.1接口ID进行编译,这是运行这些组件的服务器返回的接口。 所有客户端都使用早在1999年生成的COM应用程序代理。我定义接口的类型库包括以下行:
解释了为什么他们希望在我的方法的输出参数中使用Recordset 2.1版。显然问题出在我的2003年重新编译问题上,那时_Recordset符号不再与2.1版相对应。确实,_Recordset对应于2.5版本,具有不同的接口ID。对我来说,解决方案是在C代码中将所有引用从_Recordset更改为Recordset21。我重建了组件并将它们部署到新服务器上。瞧-客户似乎又高兴了。 最后,还有两个困扰我的问题。 为什么代理/存根基础结构对于Vista客户端的行为似乎有所不同?与XP相比,Vista似乎对从方法参数返回的接口ID进行了更严格的检查。 我应该如何在1999年用不同的方式对此编码,以免发生这种情况?接口应该是不可变的,当我在较新版本的MDAC下重新编译时,我无意中更改了接口,因为这些方法现在返回了另一个Recordset接口作为输出参数。据我所知,当时的类型库没有特定于版本的符号-也就是说,MDAC类型库的更高版本定义了Recordset21,但该符号在2.1类型库中不可用。 当Microsoft掌握安全原则时,DCOM(和底层的RPC)引起了很多关注,并且确实进行了一些更改以关闭安全漏洞,从而导致更加严格的封送处理。我很惊讶您在Vista中看到了这一点,但在XP中却没有看到,但是有可能为Vista添加了其他检查。另外,可能在Vista中将XP中的可选严格性强制为必需。 尽管我对MDAC的了解不多,无法知道是否可以防止这种情况的发生,但我确实知道安全性是Microsoft愿意牺牲向后兼容性的少数领域之一,因此您可能无法在1999年做过任何"更好"的事情。 |