У нас есть некоторый устаревший код, который использует MSXML и классы-оболочки, сгенерированные с использованием Visual Studio C ++ #import
Директива такова:
#import <msxml6.dll> named_guids
Мы обновляем проект для использования wchar_t
как встроенный тип (ранее /Zc:wchar_t-
флаг был установлен, так wchar_t
было unsigned short
). Кажется, это вызывает проблемы, так как заголовки библиотеки типов генерируются с использованием #import
замещать const wchar_t*
входные параметры с unsigned short*
,
Например, ISAXXMLReader::putProperty
способ имеет следующее подпись:
HRESULT putProperty(
[in] const wchar_t * pwchName,
[in] VARIANT varValue);
но сгенерированный заголовок библиотеки типов использует следующую подпись:
HRESULT ISAXXMLReader::putProperty (
unsigned short * pwchName,
const _variant_t & varValue )
так не только wchar_t
конвертировано в unsigned short
, но const лишен. Таким образом, код не может быть скомпилирован без неприглядного приведения:
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());
Есть ли способ получить директиву import для генерации правильных сигнатур функций в классах-оболочках?
редактировать Чтобы добавить к путанице msxml6.h
заголовок объявляет класс C ++ ISAXXMLReader
с ожидаемой подписью:
virtual HRESULT STDMETHODCALLTYPE putProperty(
/* [in] */ const wchar_t *pwchName,
/* [in] */ VARIANT varValue) = 0;
хотя после прочтения предоставленного ответа, я думаю, он просто скрывает кровавые подробности. Но по крайней мере это согласуется с документацией (которая использует этот заголовок в своих примерах).
Комментарий Криса имеет хорошую ссылку, которая довольно четко описывает проблему. Подвести итоги:
Проблема в том, что подпись этого аргумента действительно является unsigned short *
и не const wchar_t*
Несмотря на то, что MSDN желает думать об обратном.
В некотором смысле, подпись в MSDN описывает моральное намерение параметра, а не его фактическую подпись.
Окончательным авторитетом для подписи является сама библиотека типов MSXML6. Как описывает ссылка в комментарии Криса, в библиотеке типов нет способа указать, что аргумент является «указателем на широкий символ», потому что автоматизация не поддерживает такую вещь. Таким образом, они используют самую близкую вещь, которая совместима с ABI, и это unsigned short *
,
#import
Расширение компилятора может отражать только то, что находится в библиотеке типов. Нельзя сказать, чтобы он выборочно «лгал» в выводе.
Вот фактическая подпись этого метода, взятая прямо из библиотеки типов (через oleview.exe):
HRESULT _stdcall putProperty(
[in] unsigned short* pwchName,
[out, retval] VARIANT* pvarValue);
(У меня есть несколько рук, использующих oleview. В конце концов, вы смотрите на вывод генератора кода, как и в #import, так что он не доказывает ничего нового. Однако это лучшее, что мы можем обойтись без использования API библиотеки типов, чтобы самим посмотреть библиотеку типов).
Подобные вещи — это просто цена, которую вы платите за то, чтобы сделать ваш COM-объект доступным для клиентов автоматизации.
ДОПОЛНЕНИЕ:
Если вы посмотрите на интерфейс, вам будет интересно, как, черт возьми, вы можете позвонить тот из VB6 или VBScript. Что ж. ты не можешь
SAXXMLReader
Coclass реализует два почти одинаковых интерфейса с одинаковой семантикой: ISAXXMLReader
это интерфейс, на который мы смотрим, и это не удаленная, не автоматизированная, C ++ — оптимизированная версия интерфейса. Что вы получаете, когда вы используете SAXXMLReader
объект из VB6 является его [default]
интерфейс IVBSAXXMLReader
, Это интерфейс, совместимый с автоматизацией наследования IDispatch, но он имеет ту же семантику, что и ISAXXMLReader
, Для остроумия: IVBSAXXMLReader
«s putProperty
занимает BSTR
вместо unsigned short *
,
Документация MSDN для многих классов имеет тенденцию запутывать различие между тем, как объект вызывается из C ++ и VB / VBScript. Они создают видимость того, что вы вызываете одно и то же, но часто это не так, и скрывают детали интерфейса под ковриком. Я бы предпочел, чтобы они были немного более явными. Я предполагаю, что они должны в полной мере документировать семантику библиотеки, и должны обслуживать как нативных разработчиков, так и разработчиков сценариев, которые могут иметь совершенно разные уровни знаний в области сантехники COM.