msxml 6.0 dll 导入问题

问题现象:

Windows 10操作系统下编译现win7编译64位通过的工程,出现如下错误:

1>.\xxx.cpp(20) : warning C4192: 导入类型库“ISequentialStream”时自动排除“Msxml6.dll”
1>.\xxx.(20) : warning C4192: 导入类型库“_FILETIME”时自动排除“Msxml6.dll”
1>.\xxx.0.cpp(359) : error C2039: “DOMDocument”: 不是“MSXML2”的成员

代码片段:

#include "stdafx.h"
#ifndef _M_X64
#import "Msxml4.dll"
#else
#import "Msxml6.dll"
#endif

	BOOL WINAPI Function(const _bstr_t& bstrXml, LPSEDL_INFO lpSedlInfo)
	{
		MSXML2::IXMLDOMDocument2Ptr	spDOMDoc =	NULL;
		VARIANT_BOOL	vtBool	                 =	VARIANT_TRUE;
		try
		{
			if(FAILED(spDOMDoc.CreateInstance(__uuidof(MSXML2::DOMDocument/*40*/))))
			{
				::OutputDebugString(_T("创建读SEDL文件组件失败!"));
				return	FALSE;
			}
                }
                /*其余代码省略*/
         }

定位过程:

再次工程已经确认windows 7 编译确实顺利通过,包括重新构建等常识;

        通过vs右键打开源代码对应的文件功能类似include功能,发现msxml6.0文件找不到,最初怀该文件丢失;

        尝试从其他ok的版本拷贝到改工程附件包含头文件的目录下/I配置下,发现问题任然出现;

        后来得知需要单独安装msxml 过程发现msxml6已经安装,通过文件搜索确认该文件确实已经存在 在%SYSTEM%\目录下 C:\Windows\SysWOW64和C:\Windows\System32均有,当然此处编译的64位所以只关心前者。

        对比Windows 10的 msxml6.dll和Windows 7的msxml6.dll发现居然不一样,并且通过生成的导出msxml6.tlh 和msxml6.tli,确认Windows10的生成他tlh文件中缺失 DOMDument定义,这就解释为啥会有这个问题了。 为什么Windows 10 和Windows 7下的这个文件差异 会丢失DOMDocument定义,导致不兼容,通过搜索怀疑应该是摒弃太老的版本的功能,主推msxml6.0的特性吧。

        下面分别附上对应dll的对比和生成tlh文件对比差异如下:

Windows10 Windows 7

1,980,768 字节
6.30.14393.3216.30.14393.321Windows NT, Windows 32 bitDLL语言中性, Unicode6.30.14393.321MSXML 6.0Microsoft XML Core Services6.30.14393.321Microsoft Corporation© Microsoft Corporation. All rights reserved.MSXML6.dllMSXML6.dll

2,001,408 字节
6.30.7600.171576.30.7600.17157Windows NT, Windows 32 bitDLL语言中性, Unicode6.30.7600.17157MSXML 6.0 SP3Microsoft(R) MSXML 6.0 SP36.30.7600.17157 Microsoft CorporationCopyright (C) Microsoft Corporation. 1981-2008MSXML6.dllMSXML6.dll

        

 

可以看到版本信息不一样 一个是msxml 6.0 sp 3 ,同时,对比生成的tlh文件发现,windows 7的文件中有DOMDocument,并且该定义实际的uuid 对应是msxml 2.0:

struct __declspec(uuid("f6d90f11-9c73-11d3-b32e-00c04f990bb4"))
DOMDocument;
    // [ default ] interface IXMLDOMDocument2
    // [ default, source ] dispinterface XMLDOMDocumentEvents


至此问题算是搞清楚了。


那么如何解决呢? 

因为工程代码里面比较多,一个解决办法是把DOMDocument名称全部替换成DOMDocument60 ,但是这个不是一个良好的解决办法,因为会导致兼容性问题。如果这样改,那么要求产品实际运行环境必须由msxml6.dll的环境,而通过上面分析发现实际上只需要msxml2 或者msxml3 。

还有另外一个解决办法就是在工程里面使用我们指定的msxml6.dll,而不用Windows 10系统自带的。

中间我做过尝试把目标dll项目配置选项的/I附件目录下,尝试不成功; 放在改cpp对应的目录下是可以的,但是由于文件比较多工程的项目也比较多,不太可能放到每个项目目录下。

于是研究了一下#import指令导入文件的搜索顺序(摘取msdn描述):

filename 后可跟目录规范(可选)。 文件名必须命名现有文件。 两种语法形式之间的差异在于预处理器在未完整指定路径时搜索类型库文件的顺序。

语法形式 操作
带引号的形式 指示预处理器首先在包含 #import 语句的文件目录中查找类型库,然后在包含 (#include) 该文件的任何文件目录中查找类型库文件。 然后预处理器沿如下所示的路径执行搜索。
尖括号形式 指示预处理器沿下列路径搜索类型库文件:

1. PATH 环境变量路径列表
2. LIB 环境变量路径列表
3. /I(附加包含目录)编译器选项指定的路径,但该编译器搜索另一具有 no_registry 特性的类型库引用的类型库。
从描述上因为/I 配置的附件目录是放到最后的,而PATH路径的顺序在前,所以编译过程中,还是导入了系统的dll。所以,你也许一眼看出了解决方案。对,就是在PATH环境变量中指定特定msxml6.dll版本,并且保证在对应的系统目录前即可。具体设置环境变量操作再次就不赘述了。

至此,在不改动原来项目代码的情况下,达成了Windows 10编译的目标。

心得:

通过本次定位过程,了解msxml发展过程、深入熟悉了#import指令、Windows10系统下获取TrustedInstaller 权限修改系统文件的方法、同时再次熟悉了向前兼容和向后兼容差异。


你可能感兴趣的:(编程语言)