简体   繁体   English

#import指令创建的COM包装器类将wchar_t替换为unsigned short

[英]#import directive created COM wrapper classes replaces wchar_t with unsigned short

We have some legacy code that uses MSXML and the wrapper classes generated using Visual Studio's C++ #import directive like so: 我们有一些使用MSXML的旧代码,以及使用Visual Studio的C ++ #import指令生成的包装器类,如下所示:

#import <msxml6.dll> named_guids

We are upgrading the project to use wchar_t as a built-in type (previously, the /Zc:wchar_t- flag was set, so wchar_t was unsigned short ). 我们正在升级项目,以将wchar_t用作内置类型(以前已设置了/Zc:wchar_t-标志,因此wchar_tunsigned short )。 This seems to cause problems as the type library headers generated using #import replace const wchar_t* input parameters with unsigned short* . 这似乎引起问题,因为使用#import生成的类型库标头将const wchar_t*输入参数替换为unsigned short*

For example the ISAXXMLReader::putProperty method has the following signature : 例如, ISAXXMLReader::putProperty方法具有以下签名

HRESULT putProperty(
    [in] const wchar_t * pwchName,
    [in] VARIANT varValue);

but the generated type library header uses the following signature: 但是生成的类型库标头使用以下签名:

HRESULT ISAXXMLReader::putProperty ( 
    unsigned short * pwchName, 
    const _variant_t & varValue )

so not only is wchar_t converted to unsigned short , but the const is stripped. 因此,不仅将wchar_t转换为unsigned short ,而且还删除了const。 So the code fails to compile without an unsightly cast: 因此,如果不进行难看的转换,代码将无法编译:

MSXML2::ISAXXMLReaderPtr saxReader(__uuidof(MSXML2::SAXXMLReader60));
MSXML2::IMXWriterPtr xmlWriter(__uuidof(MSXML2::MXXMLWriter60));

//Set properties on the XML writer.
// Omitted for brevity

saxReader->putProperty(L"http://xml.org/sax/properties/lexical-handler", // Can't convert to unsigned short*
            (_variant_t)xmlWriter.GetInterfacePtr());

Is there any way to get the import directive to generate the proper function signatures in the wrapper classes? 有什么方法可以使import指令在包装类中生成正确的函数签名?

Edit To add to the muddle the msxml6.h header declares a C++ class ISAXXMLReader with the expected signature: 编辑要添加到混乱中, msxml6.h标头声明了具有预期签名的C ++类ISAXXMLReader

    virtual HRESULT STDMETHODCALLTYPE putProperty( 
        /* [in] */ const wchar_t *pwchName,
        /* [in] */ VARIANT varValue) = 0;

though after reading the answer provided, I guess it's just hiding the gory details. 尽管在阅读了提供的答案之后,我想它只是隐藏了血腥的细节。 But at least it's consistent with the documentation (which uses this header in its samples.) 但至少与文档一致(该示例在其示例中使用此标头)。

Chris' comment has a good link which describes the problem pretty cleanly. 克里斯的评论有一个很好的链接,清楚地描述了问题。 To summarize: 总结一下:

The problem is that the signature of that argument really is unsigned short * and not const wchar_t* , despite MSDN's wishful thinking to the contrary. 问题是该参数的签名实际上unsigned short *而不是const wchar_t* ,尽管MSDN的一厢情愿与此相反。

In a way, the signature in MSDN describes the moral intent of the parameter, not its actual signature. 在某种程度上,MSDN中的签名描述了参数的道德意图,而不是其实际签名。

The ultimate authority on what is the signature is the MSXML6 type library itself. 关于签名的最终授权是MSXML6类型库本身。 As the link in Chris' comment describes, there is no way to indicate in a type library that an argument is a "pointer to a wide character" because automation doesn't support such a thing. 正如克里斯评论中的链接所描述的那样,由于自动化不支持这样的事情,因此无法在类型库中指出参数是“指向宽字符的指针”。 So, they use the closest thing that is ABI-compatible, and that's a unsigned short * . 因此,他们使用与ABI兼容的最接近的东西,这是一个unsigned short *

The #import compiler extension can only reflect what's in the type library. #import编译器扩展只能反映类型库中的内容。 There is no way to tell it to selectively "lie" in the output. 没有办法告诉它有选择地“躺在”输出中。

Here's the actual signature of that method, taken straight from the type library (via oleview.exe): 这是该方法的实际签名,直接从类型库中获取(通过oleview.exe):

HRESULT _stdcall putProperty(
                  [in] unsigned short* pwchName, 
                  [out, retval] VARIANT* pvarValue);

(there is a sleigh of hands in me using oleview. After all, you're looking at the output of a code generator just like with #import, so it doesn't quite prove anything new. However, this is the best we can do without using the type library API to look at the type library ourselves) . (使用oleview时,我手牵着手。毕竟,您正在像#import一样查看代码生成器的输出,因此并没有证明什么新东西。但是,这是我们所能做到的最好的无需使用类型库API自己查看类型库)

This kind of things is just the price you have pay for making your COM object available to automation clients. 这种事情仅仅是使COM对象可用于自动化客户端的价格。

ADDENDUM: 附录:

If you look at the interface, you have to wonder how the heck you can possibly call that from VB6 or VBScript. 如果看一下接口,您必须想知道如何从VB6或VBScript调用 Well. 好。 you can't. 你不能。

The SAXXMLReader coclass implements two nearly-twin interfaces with the same semantics: ISAXXMLReader is the interface we're looking at, and it's a non-remotable, non-automation, C++-optimized version of the interface. SAXXMLReader类实现了两个具有相同语义的近乎双胞胎的接口: ISAXXMLReader是我们正在关注的接口,它是该接口的不可删除,非自动化,C ++优化的版本。 What you get when you use a SAXXMLReader object from VB6 is its [default] interface IVBSAXXMLReader . 从VB6使用SAXXMLReader对象时,会得到其[default]接口IVBSAXXMLReader This is an IDispatch-inheriting automation-compatible interface, but it has the same semantics as ISAXXMLReader . 这是一个IDispatch继承的自动化兼容接口,但其语义与ISAXXMLReader相同。 To wit: IVBSAXXMLReader 's putProperty takes a BSTR instead of an unsigned short * . IVBSAXXMLReaderIVBSAXXMLReaderputProperty采用BSTR而不是unsigned short *

The MSDN documentation for many classes tends to muddle the distinction between how an object is called from C++ and VB/VBScript. 许多类的MSDN文档都倾向于混淆如何从C ++和VB / VBScript调用对象之间的区别。 They make it look like you are calling the same thing when often that's not the case, and they hide the interface details under the rug. 它们使您看起来好像经常在拨打相同的电话,而事实并非如此,并且它们将接口详细信息隐藏在地毯下。 I would prefer if they were a bit more explicit. 我希望它们更明确。 I guess they have to the balance documenting the semantics of a library, and having to cater to both native and scripting developers, who might have vastly different levels of expertise on COM's plumbing. 我想他们必须平衡地记录库的语义,并且必须迎合本机和脚本开发人员,他们可能在COM管道方面的专业知识水平差异很大。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM