MSXML2 :: IXMLDOMDocument2Ptr-> GetXML () портит мою строку! - PullRequest
1 голос
/ 27 ноября 2008

All

это мой код

//declare string pointer
BSTR markup;

//initialize markup to some well formed XML <-

//declare and initialize XML Document
MSXML2::IXMLDOMDocument2Ptr pXMLDoc;
HRESULT hr;
hr = pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40));
pXMLDoc->async = VARIANT_FALSE;
pXMLDoc->validateOnParse = VARIANT_TRUE;
pXMLDoc->preserveWhiteSpace = VARIANT_TRUE;    

//load markup into XML document
vtBoolResult = pXMLDoc->loadXML(markup);

//do some changes to the XML file<-

//get back string from XML doc
markup = pXMLDoc->Getxml(); //<-- this retrieves RUBBISH

На данный момент моя строка искажена (всего несколько китайских символов в начале, а затем мусор). Похоже на проблему с кодировкой.

Я также попробовал следующее:

_bstr_t superMarkup = _bstr_t(markup);

//did my stuff

superMarkup = pXMLDoc->Getxml();

markup = superMarkup; 

но все равно я получаю тот же результат.

Даже если я вызываю GetXML (), ничего не меняя в документе xml, я все равно получаю мусор.

В этот момент, если я попытаюсь присвоить искаженный указатель другому указателю, будет выдано сообщение об ошибке:

Попытка восстановления защищена от записи объем памяти. это часто указание эта другая память повреждена.

Есть предложения?

EDIT1:

Я обнаружил, что это происходит в связи с размером строки XML. Если это произойдет с заданной строкой XML, и я уменьшу размер (сохраняя ту же схему), он будет работать нормально. Похоже, MSXML2 :: DOMDocument40 имеет ограничение по размеру? Подробно это произойдет, если у меня будет более 16407 символов. У меня есть еще один GetXML, который получит RUBBISH - если он <= 16407, все работает нормально. </strong>

EDIT2:

Родди был прав - мне не хватало того, что _bstr_t это класс ...

Звонит ли какой-нибудь колокол?

Приветствия

Ответы [ 4 ]

4 голосов
/ 27 ноября 2008

Попробуйте заменить

 BSTR Markup;

с

 bstr_t Markup;

BSTR в значительной степени тупой указатель, и я думаю, что возвращаемый результат GetXML () преобразуется во временный, который затем уничтожается, когда вы его видите. bstr_t оборачивает это с некоторой долей умного указателя ...

Примечание: ваша вещь "SuperMarkup" НЕ сделала то, что я предложил. Опять же, BSTR является просто указателем и не «владеет» тем, на что он указывает. bstr_t, с другой стороны, делает. Я думаю, что ваша функция GetXML () возвращает bstr_t, который затем удаляется по мере того, как он выходит из области видимости, а ваш BSTR указывает на недопустимую память.

1 голос
/ 05 декабря 2008

Это код, который я написал ранее с небольшой модификацией, которая добавляет 20000 «дочерних» элементов :), и он хорошо работает.

extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, 
                                LPTSTR /*lpCmdLine*/, int nShowCmd)
{
    CoInitialize(NULL);
    {
        //declare string pointer
        _bstr_t                           markup;
        //initialize markup to some well formed XML <-
        //declare and initialize XML Document
        try {
            MSXML2::IXMLDOMDocument2Ptr   pXMLDoc;
            HRESULT                       hr              = pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument));    
            pXMLDoc->async                = VARIANT_FALSE;
            pXMLDoc->validateOnParse      = VARIANT_TRUE;
            pXMLDoc->preserveWhiteSpace   = VARIANT_TRUE;    

            //load markup into XML document
            VARIANT_BOOL                  vtBoolResult    = pXMLDoc->loadXML(L"<XML></XML>");

            for (int i = 0; i < 20000; i++) {
                MSXML2::IXMLDOMNodePtr    node            = pXMLDoc->createNode(_variant_t("element"), _bstr_t("child"), _bstr_t(""));

                if (node)
                    pXMLDoc->documentElement->appendChild(node);
            }

            //do some changes to the XML file<-
            //get back string from XML doc
            markup = pXMLDoc->Getxml(); //<-- th
            ATLTRACE("XML lenght = %d, xml=%S\n", markup.length(), (BSTR)markup.GetBSTR());
        } catch(_com_error e) {
            ATLTRACE("error = %S\n", (BSTR)e.ErrorMessage());
        }
    }
    CoUninitialize();
    return _AtlModule.WinMain(nShowCmd);
}

это производит 1024 строки вывода, однако в отладчике, но это может легко вывести xml в stdoutput, если вы хотите. Это вывод, который я получаю до сих пор

'getxmltest.exe': Loaded 'C:\Windows\winsxs\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.6001.18000_none_5cdbaa5a083979cc\comctl32.dll'
XML lenght = 160013, xml=<XML><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><child/><'getxmltest.exe': Unloaded 'C:\Windows\SysWOW64\msxml3.dll'
The program '[4884] getxmltest.exe: Native' has exited with code 0 (0x0).
1 голос
/ 27 ноября 2008

Я не очень разбираюсь в этой конкретной библиотеке xml, однако:

Здесь стоит обратить внимание на то, что исходный вопрос переписал переменную 'разметка', когда он получил результат. Многие анализаторы XML возвращают указатели на начальный ввод (т.е. разметку), поэтому, когда вы заменяете его на вывод, вы также удаляете ввод в анализатор XML.

Возможно, этот процесс сделает недействительной только что полученную строку. Вы заметите, что Эухенио Миро не делает эту ошибку в своем примере, так как он выделяет другую переменную для хранения ввода (pXMLDoc).

Быстрый тест, который вы можете сделать, это изменить

//get back string from XML doc
markup = pXMLDoc->Getxml(); //<-- this retrieves RUBBISH

до

//get back string from XML doc
BSTR output = pXMLDoc->Getxml(); //<-- perhaps this doesn't

и посмотри, имеет ли это значение.

1 голос
/ 27 ноября 2008

Хорошо, я думаю, что Патрик прав. Я взял ваш код и сделал быстрый проект ATL EXE с именем getxmltest. Я добавил эту строку после директив #include

#import "MSXML3.DLL"

удалено событие после сборки, которое регистрирует компонент, потому что я не хочу показывать какой-либо компонент из exe, но уже есть ссылки на все заголовки и библиотеки ATL, и добавил следующий код в _tWinMain

extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, 
                                LPTSTR /*lpCmdLine*/, int nShowCmd)
{
    CoInitialize(NULL);
    {
        //declare string pointer
        _bstr_t                     markup;
        //initialize markup to some well formed XML <-
        //declare and initialize XML Document
        MSXML2::IXMLDOMDocument2Ptr pXMLDoc;
        HRESULT                     hr              = pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument));

        pXMLDoc->async              = VARIANT_FALSE;
        pXMLDoc->validateOnParse    = VARIANT_TRUE;
        pXMLDoc->preserveWhiteSpace = VARIANT_TRUE;    

        //load markup into XML document
        VARIANT_BOOL                vtBoolResult    = pXMLDoc->loadXML(L"<XML></XML>");

        //do some changes to the XML file<-
        //get back string from XML doc
        markup = pXMLDoc->Getxml(); //<-- this retrieves RUBBISH (not anymore...)
        ATLTRACE("%S", (BSTR)markup.GetBSTR());
    }
    CoUninitialize();
    return _AtlModule.WinMain(nShowCmd);
}

Полученные линии трассировки были следующими ...

'getxmltest.exe': Loaded 'C:\Windows\winsxs\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.6001.18000_none_5cdbaa5a083979cc\comctl32.dll'
<XML></XML>
'getxmltest.exe': Unloaded 'C:\Windows\SysWOW64\msxml3.dll'
The program '[6040] getxmltest.exe: Native' has exited with code 0 (0x0).

Где мы можем увидеть строку, которую мы ввели изначально ... Я не добавил никакой логики в код, потому что мне показалось, что этого было достаточно для отображения получающегося xml после обработки его с помощью механизма MSXML. Очевидно, что вы можете провести дополнительное тестирование с использованием этого кода и посмотреть, что будет дальше.

...