c++ - 传递字节的 SAFEARRAY 以加载 MSXML 的函数

标签 c++ xml windows msxml safearray

如果有好心人请通过以下来源告诉我为什么 MSXML“加载”函数无法加载此 XML。

我在这里尝试使用 MSXML 解析器的“加载”函数加载 UTF-8 编码的 XML。我有一个 BSTR [UTF-16 编码] 作为参数,所以我试图将它转换为字节的 SAFEARRAY,以便我可以将它传递给 MSXML 的“加载”函数。但问题是加载函数无法加载此 XML。如果有人可以提供解决方案,我将不胜感激。

#include <windows.h>
#include <objsafe.h>
#include <objbase.h>
#include <atlbase.h>
#include <string>
#include <comutil.h>
#include <msxml2.h>
#include <iostream>

using namespace std;

#define STATUS_SUCCESS 0
#define STATUS_FAIL -1

long LoadXmlData(BSTR xmlDoc)
{
HRESULT hr = S_OK;
CComPtr <IXMLDOMDocument> xmlDomDoc = NULL;
CComPtr <IXMLDOMElement> docRoot = NULL;
VARIANT_BOOL isParseSucess = FALSE;

CoInitialize(NULL);
hr = xmlDomDoc.CoCreateInstance(__uuidof(DOMDocument30));
if (FAILED(hr))
{
    return STATUS_FAIL;
}

BYTE HUGEP *pByte;
int len = WideCharToMultiByte(CP_UTF8, 0, xmlDoc, -1, NULL, 0, NULL, NULL);
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].cElements = len;
rgsabound[0].lLbound = 0;

SAFEARRAY* psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
if (psa != NULL)
{
    hr = SafeArrayAccessData(psa, (void HUGEP**)&pByte);
    if (!FAILED(hr))
    {
        if (len > 0)
        {
            WideCharToMultiByte(CP_UTF8, 0, xmlDoc, -1, (LPSTR)&pByte[0], len, NULL, NULL);
            //cout << "Converted Byte Array: " << pByte << endl << endl;
        }
        else
        {
            return STATUS_FAIL;
        }
        SafeArrayUnaccessData(psa);
    }
}

VARIANT v;
VariantInit(&v);
V_VT(&v) = VT_ARRAY | VT_UI1;
V_ARRAY(&v) = psa;

hr = xmlDomDoc->load(v, &isParseSucess);
//hr = xmlDomDoc->loadXML(xmlDoc, &isParseSucess); //can't use this function because XML is encoded in UTF-8

if (FAILED(hr) || (!isParseSucess))
{
    return STATUS_FAIL;
}
else
{
    return STATUS_SUCCESS;
}
}

int main()
{
BSTR xmlDoc = SysAllocString(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?> <response> </response> ");
long ret = LoadXmlData(xmlDoc);
if (ret == STATUS_SUCCESS)
{
    cout << "MSXML: loading the XML succeeded";
}
else
{
    cout << "MSXML: loading the XML failed";
}
//string str;
//getline(cin, str);
return 0;
}

ps:如果有人尝试编译此源,您可能会在第一次遇到链接错误,请在 VS 设置中将 comsuppw.lib 添加为链接器依赖项。 XML 是 UTF-8 编码的,所以我不能在 MSXML 中使用“LoadXML”函数。

最佳答案

XML 文件是 UTF-8 但这里不需要转换,因为 Windows 函数会在需要时自动在 UTF-16 和 UTF-8 之间转换(除非输入/输出是 BYTE*... )

BSTR 需要清理。您可以使用具有自动清理功能的 CComBSTR(str)

您可以使用const wchar_t* 将字符串传递给您自己的函数。 BSTR 是 COM 等所必需的。

如注释中所述,IXMLDOMDocument::load 需要一个文件名作为输入。在这种情况下使用 IXMLDOMDocument::loadXML

#include <iostream>
#include <windows.h>
#include <atlbase.h>
#include <msxml2.h>

long LoadXmlData(const wchar_t* content)
{
    HRESULT hr = S_FALSE;
    CComPtr<IXMLDOMDocument> doc = NULL;
    CComPtr<IXMLDOMElement> docRoot = NULL;

    hr = doc.CoCreateInstance(__uuidof(DOMDocument30));
    if(FAILED(hr))
        return S_FALSE;

    VARIANT_BOOL is_success = FALSE;
    CComBSTR arg(content);
    hr = doc->loadXML(arg, &is_success);

    //if you are loading from a file:
    //hr = doc->load(CComVariant(L"c:\\test\\test.xml"), &is_success);

    if(FAILED(hr) || !is_success)
        return S_FALSE;

    //if save is needed:
    //doc->save(CComVariant(L"c:\\test\\test.xml"));
    return S_OK;
}

int main()
{
    CoInitialize(NULL);

    //ελληνική γλώσσα Greek text for testing
    CComBSTR data(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response>ελληνική γλώσσα</response>");
    long ret = LoadXmlData(data);
    if(ret == S_OK)
        std::cout << "MSXML: loading the XML succeeded\n";
    else
        std::cout << "MSXML: loading the XML failed\n";

    CoUninitialize();
    return 0;
}

关于c++ - 传递字节的 SAFEARRAY 以加载 MSXML 的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46741048/

相关文章:

c++ - 初始化匿名 union 的语法

c++ - 改变全局变量

c++ - OpenGL "black screen"挫折

c# - Windows UWP应用中的MediaElement无法播放音频

windows - Interix 是否实现 fork()?

java - 需要使用 TCP 和 OpenSSL 将 Java 客户端连接到 Cpp 服务器

android - 如何在android中将底部阴影添加到选项卡布局或工具栏

java - 在 Spring MVC 中实现 XSLT View

xml - 重新定义 xsd 元素

.net - Windows重启后如何自动启动自己的可执行文件?