C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组)
开发环境:Visual Studio 2010
运行环境:Windows XP SP3
第一节 读取XML文件(使用wchar_t[]字符数组)
读取XML文件可使用IXMLDOMDocument_load函数。
/* 这个程序只能在C编译器下编译成功, 请确保源文件的扩展名为c */
#define COBJMACROS
#include <stdio.h>
#include <MsXml6.h>#pragma comment(lib, "msxml6.lib")/*
参考资料:(1) VARIANT结构体: https://msdn.microsoft.com/en-us/library/windows/desktop/dd373687(v=vs.85).aspxVARIANT用于表示一个弱类型的变量(2) BSTR字符串: https://msdn.microsoft.com/en-us/library/windows/desktop/ms221069(v=vs.85).aspxBSTR字符串是用于COM组件对象模型的字符串格式, 字符串以表示字符串长度的4字节整数开始, 然后跟上UTF-16编码的wchar_t字符串(包括\0结束标志)。BSTR类型的变量是一个指针, 指向字符串的第一个字符处例如, 一段起始地址为1000的内存空间, 则1000~1003这四个字节存放字符串的长度, 1004开始才是字符串的真正内容, BSTR变量应指向1004而不是1000wchar_t *用于保存UTF-16编码格式的字符串, 用wprintf的%ls输出char *可以用来保存任意编码格式的字符串, 但只有ANSI格式才能使用printf的%s正确显示出来在简体中文版操作系统下, ANSI就是GB2312编码MultiByteToWideChar函数可以将char *字符串转换为wchar_t *字符串WideCharToMultiByte函数可以将wchar_t *字符串转换为char *t字符串SysAllocString函数可以将wchar_t *字符串转换为BSTR字符串(3) IXMLDOMDocument接口: https://msdn.microsoft.com/en-us/library/windows/desktop/dd892951(v=vs.85).aspx(4) 组件对象模型COM: https://msdn.microsoft.com/en-us/library/windows/desktop/ff485848(v=vs.85).aspxhttps://msdn.microsoft.com/en-us/library/windows/desktop/ms680573(v=vs.85).aspx(5) Windows窗口程序: https://msdn.microsoft.com/en-us/library/windows/desktop/ff381409(v=vs.85).aspx
*/// C语言自带的wprintf函数无法打印中文
// 所以这里重新实现一个能打印中文的my_wprintf函数
int my_wprintf(const wchar_t *format, ...)
{int n;va_list list;wchar_t str[1024];DWORD ret;HANDLE console;va_start(list, format);n = _vsnwprintf_s(str, _countof(str), _countof(str) - 1, format, list);va_end(list);console = GetStdHandle(STD_OUTPUT_HANDLE);WriteConsoleW(console, str, (DWORD)wcslen(str), &ret, NULL);return n;
}// 显示元素节点的属性值 (元素节点是一种节点)
void display_attribute(IXMLDOMElement *elem, const wchar_t *name, int intval)
{int num;BSTR bstr; // 表示一个字符串VARIANT variant; // 表示一个弱类型的变量bstr = SysAllocString(name); // 必须用SysAllocString函数把wchar_t *字符串转换成BSTR字符串IXMLDOMElement_getAttribute(elem, bstr, &variant);SysFreeString(bstr); // 使用完字符串后必须释放my_wprintf(L"[Attribute] name=%ls, value=%ls", name, variant.bstrVal); // BSTR和wchar_t *字符串都用%ls输出if (intval){num = _wtoi(variant.bstrVal); // 转换为整形printf(", 2*value=%d", 2 * num);}printf("\n");SysFreeString(variant.bstrVal); // 保存在Variant中的BSTR也必须释放掉
}// 显示节点名称
void display_nodename(IXMLDOMNode *node)
{BSTR bstr;IXMLDOMNode_get_nodeName(node, &bstr);my_wprintf(L"[Node] name=%ls\n", bstr); // 使用%ls打印BSTR字符串内容SysFreeString(bstr); // 使用完字符串后必须释放
}// 显示节点中的文本内容 (方法一)
void display_content(IXMLDOMNode *node)
{BSTR text;IXMLDOMNode_get_text(node, &text);my_wprintf(L"[Text] %ls\n", text);SysFreeString(text);
}// 显示节点中的文本内容 (方法二)
// 文本内容是文本节点, 是node节点下的子节点
/*
void display_content(IXMLDOMNode *node)
{IXMLDOMNode *child;VARIANT value;IXMLDOMNode_get_firstChild(node, &child); // 获取文本节点IXMLDOMNode_get_nodeValue(child, &value); // 得到文本节点的内容my_wprintf(L"[Text] %ls\n", value.bstrVal);SysFreeString(value.bstrVal);IXMLDOMNode_Release(child);
}
*/// 获取节点中的XML文本内容
void display_inner_xml(IXMLDOMNode *node)
{BSTR bstr;IXMLDOMNode_get_xml(node, &bstr);my_wprintf(L"[InnerXML] %ls\n", bstr);SysFreeString(bstr);
}void read_xml(IXMLDOMDocument *xmldoc)
{long i, len;IXMLDOMElement *root;IXMLDOMElement *elem;IXMLDOMNode *root_node;IXMLDOMNode *item;IXMLDOMNodeList *list;// 根节点IXMLDOMDocument_get_documentElement(xmldoc, &root);IXMLDOMNode_QueryInterface(root, &IID_IXMLDOMNode, &root_node); // 把element node变为nodedisplay_nodename(root_node);display_attribute(root, L"id", 1);display_inner_xml(root_node);printf("\n");// 根节点下的子节点IXMLDOMElement_get_childNodes(root, &list);IXMLDOMNodeList_get_length(list, &len);for (i = 0; i < len; i++){IXMLDOMNodeList_get_item(list, i, &item);display_nodename(item);display_content(item);// 只有元素节点才有属性节点, 所以获取属性前要进行类型转换, 把node变为element nodeIXMLDOMNode_QueryInterface(item, &IID_IXMLDOMElement, &elem);display_attribute(elem, L"name", 0);IXMLDOMElement_Release(elem);IXMLDOMNode_Release(item);}IXMLDOMNodeList_Release(list);IXMLDOMNode_Release(root_node);IXMLDOMElement_Release(root);
}// 打开XML文件
void open_xml(const wchar_t *name)
{HRESULT hr;IXMLDOMDocument *xmldoc;VARIANT filename;VARIANT_BOOL flag;hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);if (SUCCEEDED(hr)){filename.bstrVal = SysAllocString(name); // 将wchar_t *转换为BSTRfilename.vt = VT_BSTR;IXMLDOMDocument_load(xmldoc, filename, &flag);// 注: IXMLDOMDocument_load是读XML文件// IXMLDOMDocument_loadXML是读XML字符串SysFreeString(filename.bstrVal);if (flag == VARIANT_TRUE){printf("读取XML文件成功\n");read_xml(xmldoc);}elseprintf("读取XML文件失败\n");IXMLDOMDocument_Release(xmldoc);}
}int main()
{CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型open_xml(L"data.xml");CoUninitialize();return 0;
}
第二节 读取XML文件(使用char[]字符数组)
/* 这个程序只能在C编译器下编译成功, 请确保源文件的扩展名为c */
#define COBJMACROS
#include <stdio.h>
#include <MsXml6.h>#pragma comment(lib, "msxml6.lib")// char *转BSTR
// 用完后调用SysFreeString释放
BSTR convert_string_to_bstr(const char *s)
{int n;wchar_t *ws;BSTR bstr = NULL;n = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0);ws = malloc(n * sizeof(wchar_t));if (ws != NULL){MultiByteToWideChar(CP_ACP, 0, s, -1, ws, n);bstr = SysAllocString(ws);free(ws);}return bstr;
}// BSTR转char *
// 用完后调用free释放
char *convert_bstr_to_string(BSTR bstr)
{char *s;int n;n = WideCharToMultiByte(CP_ACP, 0, bstr, -1, NULL, 0, NULL, NULL);s = malloc(n);if (s != NULL)WideCharToMultiByte(CP_ACP, 0, bstr, -1, s, n, NULL, NULL);return s;
}// 显示元素节点的属性值 (元素节点是一种节点)
void display_attribute(IXMLDOMElement *elem, const char *name, int intval)
{char *value_str;int num;BSTR bstr; // 表示一个字符串VARIANT variant; // 表示一个弱类型的变量bstr = convert_string_to_bstr(name);IXMLDOMElement_getAttribute(elem, bstr, &variant);SysFreeString(bstr); // 使用完字符串后必须释放value_str = convert_bstr_to_string(variant.bstrVal);printf("[Attribute] name=%s, value=%s", name, value_str);if (intval){num = atoi(value_str); // 转换为整形printf(", 2*value=%d", 2 * num);}printf("\n");free(value_str);SysFreeString(variant.bstrVal); // 保存在Variant中的BSTR也必须释放掉
}// 显示节点名称
void display_nodename(IXMLDOMNode *node)
{char *s;BSTR bstr;IXMLDOMNode_get_nodeName(node, &bstr);s = convert_bstr_to_string(bstr);printf("[Node] name=%s\n", s);free(s);SysFreeString(bstr); // 使用完字符串后必须释放
}// 显示节点中的文本内容 (方法一)
void display_content(IXMLDOMNode *node)
{char *text_str;BSTR text;IXMLDOMNode_get_text(node, &text);text_str = convert_bstr_to_string(text);printf("[Text] %s\n", text_str);free(text_str);SysFreeString(text);
}// 显示节点中的文本内容 (方法二)
// 文本内容是文本节点, 是node节点下的子节点
/*
void display_content(IXMLDOMNode *node)
{char *value_str;IXMLDOMNode *child;VARIANT value;IXMLDOMNode_get_firstChild(node, &child); // 获取文本节点IXMLDOMNode_get_nodeValue(child, &value); // 得到文本节点的内容value_str = convert_bstr_to_string(value.bstrVal);printf("[Text] %s\n", value_str);free(value_str);SysFreeString(value.bstrVal);IXMLDOMNode_Release(child);
}
*/// 获取节点中的XML文本内容
void display_inner_xml(IXMLDOMNode *node)
{char *s;BSTR bstr;IXMLDOMNode_get_xml(node, &bstr);s = convert_bstr_to_string(bstr);printf("[InnerXML] %s\n", s);free(s);SysFreeString(bstr);
}void read_xml(IXMLDOMDocument *xmldoc)
{long i, len;IXMLDOMElement *root;IXMLDOMElement *elem;IXMLDOMNode *root_node;IXMLDOMNode *item;IXMLDOMNodeList *list;// 根节点IXMLDOMDocument_get_documentElement(xmldoc, &root);IXMLDOMNode_QueryInterface(root, &IID_IXMLDOMNode, &root_node); // 把element node变为nodedisplay_nodename(root_node);display_attribute(root, "id", 1);display_inner_xml(root_node);printf("\n");// 根节点下的子节点IXMLDOMElement_get_childNodes(root, &list);IXMLDOMNodeList_get_length(list, &len);for (i = 0; i < len; i++){IXMLDOMNodeList_get_item(list, i, &item);display_nodename(item);display_content(item);// 只有元素节点才有属性节点, 所以获取属性前要进行类型转换, 把node变为element nodeIXMLDOMNode_QueryInterface(item, &IID_IXMLDOMElement, &elem);display_attribute(elem, "name", 0);IXMLDOMElement_Release(elem);IXMLDOMNode_Release(item);}IXMLDOMNodeList_Release(list);IXMLDOMNode_Release(root_node);IXMLDOMElement_Release(root);
}// 打开XML文件
void open_xml(const char *name)
{HRESULT hr;IXMLDOMDocument *xmldoc;VARIANT filename;VARIANT_BOOL flag;hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);if (SUCCEEDED(hr)){filename.bstrVal = convert_string_to_bstr(name); // 将char *转换为BSTRfilename.vt = VT_BSTR;IXMLDOMDocument_load(xmldoc, filename, &flag);// 注: IXMLDOMDocument_load是读XML文件// IXMLDOMDocument_loadXML是读XML字符串SysFreeString(filename.bstrVal);if (flag == VARIANT_TRUE){printf("读取XML文件成功\n");read_xml(xmldoc);}elseprintf("读取XML文件失败\n");IXMLDOMDocument_Release(xmldoc);}
}int main()
{CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型open_xml("data.xml");CoUninitialize();return 0;
}
第三节 读取XML字符串(使用char[]字符数组)
读取XML字符串可使用IXMLDOMDocument_loadXML函数。
// 读取XML字符串
void load_xml_str()
{char *str = "<?xml version=\"1.0\" encoding=\"utf-8\"?><data id=\"20240117\"><post name=\"2023年人口统计数据发布了,大家怎么看?\">建档788W是主体,压哨建档出生的一部分,双胞胎三胞胎占一小部分,不建档生孩子的占一小部分,但是还是难凑出902,还是得预支一下。</post><post name=\"有什么是去了成都才知道的?\">不要跟团,也不要自驾游,成都每天都人满为患,人多车堵,还不好停车,景点大部分集中在1、2、3号线,坐地铁出行就能玩转成都。2、去鹤鸣茶社品一品茶,享受宁静时光感受成都的慢生活与惬意。3、成都火锅很辣,不是很能吃辣的朋友一定不要轻易尝试,不然会被辣的怀疑人生。</post><post name=\"能否找到一个f(x),使得当x取到全体正整数的时候,f(x)可以取到全体有理数?\">题主好像没有要求是单射啊……如果只要求满射的话,其实有个简单粗暴的做法,就是把正整数劈开……</post><post name=\"C++ 有什么好用的线程池?\">题主说的那两个thread pool其实都不错,但是2024年肯定是更推荐这一个,这个就是为进入标准的senders所实现的,学了也不会白学,当然它的使用非常简单。</post><post name=\"有什么适合大学生喝的性价比高的茶?\">虽然现代社会,买东西都在追求性价比,但茶叶这东西,我觉得还真不好说!</post></data>";BSTR bstr;HRESULT hr;IXMLDOMDocument *xmldoc;VARIANT_BOOL succeeded;hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);if (SUCCEEDED(hr)){bstr = convert_string_to_bstr(str);hr = IXMLDOMDocument_loadXML(xmldoc, bstr, &succeeded);// 注: IXMLDOMDocument_load是读XML文件// IXMLDOMDocument_loadXML是读XML字符串SysFreeString(bstr);if (SUCCEEDED(hr)){if (hr == S_OK){printf("读取XML字符串成功\n");read_xml(xmldoc);}else if (hr == S_FALSE)printf("读取XML字符串失败\n");}// 另一种判断是否成功的方式if (succeeded == VARIANT_TRUE)printf("succeeded=true\n");else if (succeeded == VARIANT_FALSE)printf("succeeded=false\n");IXMLDOMDocument_Release(xmldoc);}
}int main()
{CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型load_xml_str();CoUninitialize();return 0;
}
第四节 创建XML文件(使用char[]字符数组)
创建XML文件可使用IXMLDOMDocument_save函数。
/* 这个程序只能在C编译器下编译成功, 请确保源文件的扩展名为c */
#define COBJMACROS
#include <stdio.h>
#include <time.h>
#include <MsXml6.h>#pragma comment(lib, "msxml6.lib")// char *转BSTR
// 用完后调用SysFreeString释放
BSTR convert_string_to_bstr(const char *s)
{int n;wchar_t *ws;BSTR bstr = NULL;n = MultiByteToWideChar(CP_ACP, 0, s, -1, NULL, 0);ws = malloc(n * sizeof(wchar_t));if (ws != NULL){MultiByteToWideChar(CP_ACP, 0, s, -1, ws, n);bstr = SysAllocString(ws);free(ws);}return bstr;
}// BSTR转char *
// 用完后调用free释放
char *convert_bstr_to_string(BSTR bstr)
{char *s;int n;n = WideCharToMultiByte(CP_ACP, 0, bstr, -1, NULL, 0, NULL, NULL);s = malloc(n);if (s != NULL)WideCharToMultiByte(CP_ACP, 0, bstr, -1, s, n, NULL, NULL);return s;
}void create_header(IXMLDOMDocument *xmldoc)
{BSTR target, data;IXMLDOMNode *header_node;IXMLDOMProcessingInstruction *header;// 创建XML文档头节点target = convert_string_to_bstr("xml");data = convert_string_to_bstr("version=\"1.0\" encoding=\"utf-8\"");IXMLDOMDocument_createProcessingInstruction(xmldoc, target, data, &header);SysFreeString(target);SysFreeString(data);// header转换成node, 然后添加进文档// 注意旧的header对象和新产生的node对象都要释放IXMLDOMProcessingInstruction_QueryInterface(header, &IID_IXMLDOMNode, &header_node);IXMLDOMProcessingInstruction_Release(header);IXMLDOMDocument_appendChild(xmldoc, header_node, NULL); // 最后一个参数是输出参数, 没有用IXMLDOMNode_Release(header_node);
}IXMLDOMElement *create_root(IXMLDOMDocument *xmldoc)
{char timestr[30];struct tm tm;time_t t;BSTR name;IXMLDOMElement *root;IXMLDOMNode *root_node;VARIANT value;// 创建根节点name = convert_string_to_bstr("data");IXMLDOMDocument_createElement(xmldoc, name, &root);SysFreeString(name);// 将创建的根节点添加到文档中IXMLDOMElement_QueryInterface(root, &IID_IXMLDOMNode, &root_node);IXMLDOMDocument_appendChild(xmldoc, root_node, NULL);IXMLDOMNode_Release(root_node);// 获取当前时间time(&t);localtime_s(&tm, &t);strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &tm);// 在根节点上添加一个属性name = convert_string_to_bstr("timestr");value.bstrVal = convert_string_to_bstr(timestr);value.vt = VT_BSTR;IXMLDOMElement_setAttribute(root, name, value);SysFreeString(name);SysFreeString(value.bstrVal);return root;
}void add_post(IXMLDOMDocument *xmldoc, IXMLDOMElement *root, const char *name, const char *text)
{BSTR attrname_bstr;BSTR nodename_bstr;BSTR text_bstr;IXMLDOMElement *elem;IXMLDOMNode *node;VARIANT value;nodename_bstr = convert_string_to_bstr("post");IXMLDOMDocument_createElement(xmldoc, nodename_bstr, &elem); // 创建elementSysFreeString(nodename_bstr);IXMLDOMElement_QueryInterface(elem, &IID_IXMLDOMNode, &node); // element转nodeIXMLDOMElement_appendChild(root, node, NULL);// 添加name属性attrname_bstr = convert_string_to_bstr("name");value.bstrVal = convert_string_to_bstr(name);value.vt = VT_BSTR;IXMLDOMElement_setAttribute(elem, attrname_bstr, value);SysFreeString(attrname_bstr);SysFreeString(value.bstrVal);// 添加节点内文本text_bstr = convert_string_to_bstr(text);IXMLDOMElement_put_text(elem, text_bstr);SysFreeString(text_bstr);// 释放element和node对象// 请注意element是node的子类, 换句话说element是一种nodeIXMLDOMElement_Release(elem);IXMLDOMNode_Release(node);
}void write_xml(IXMLDOMDocument *xmldoc)
{IXMLDOMElement *root;create_header(xmldoc);root = create_root(xmldoc);add_post(xmldoc, root, "RPG Maker XP", "RPG Maker XP(RPGXP)是一款可让玩家自行制作在计算机游戏中相当受欢迎的角色扮演游戏,也就是 Role-Playing Game(RPG)的软件。制作完成的游戏,即使在没有安装 RPG Maker XP 的电脑上也能运行。");add_post(xmldoc, root, "高精度的画面", "支持 640×480 像素分辨率 32 色真彩色图像。完全对应 Alpha Channel(每个像素的透明度),光滑的透过处理,柔和的半透明表现。画面的合成方法也增加了通常的半透明合成、加算合成和减算合成。而且字型自动映射,粗体不再引人注目。");add_post(xmldoc, root, "使用软件的音乐播放", "作为 BGM,主要使用 DirectMusic Synthesizer 的 MIDI 播放。因为以软件播放,所以不能用其它格式代替,音乐素材的制造人没必需考虑对各种 MIDI 音乐的对应。在制作过程中能被正常播放的 MIDI 文件,同样可以在其它环境中正常播放。");add_post(xmldoc, root, "灵活且强大的脚本系统", "用 RPGXP 制作完成的游戏,脚本是以 Ruby 语言编写的。预先编写的脚本可以制作十分独特和有趣的游戏,它是为了更高级的游戏制作需求准备的,使用它可以进行画面设计、编写战斗系统,以及一切的游戏要素。运用脚本制作 RPG 以外类型的游戏也是可能的。");add_post(xmldoc, root, "魔塔样板", "魔塔样板是一个用RPG Maker XP、RPG Maker VX、RPG Maker Vx Ace或者VB制作的一个用来制作魔塔的样板,里面有魔塔里一些基本的地图和怪物和各种宝物。制作者只需改动怪物属性和地图,其他的都可以利用复制进行制作,制作起来方便。并且制作者还可以在魔塔样板中进行更高级的操作,做出一些特别的动画或者机关,总之,魔塔样版可以制作一切类型的魔塔。但是,有些质量较差的魔塔样板会有脚本错误。最常用版本是7630。");add_post(xmldoc, root, "房贷利息", "房贷利息是指每个月支付给银行的利息款,计算公式为:剩余未还房款×贷款利率%÷12。若贷款100万元,利率为5.88%,则第一个月要付的利息钱是100万×5.88%÷12=4900元。也就是说“钱价”为4900元/(百万元·月)。");IXMLDOMElement_Release(root);
}// 创建XML文件
void create_xml(const char *name)
{HRESULT hr;IXMLDOMDocument *xmldoc;VARIANT filename;hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);if (SUCCEEDED(hr)){write_xml(xmldoc);filename.bstrVal = convert_string_to_bstr(name); // 将char *转换为BSTRfilename.vt = VT_BSTR;hr = IXMLDOMDocument_save(xmldoc, filename);SysFreeString(filename.bstrVal);if (SUCCEEDED(hr))printf("写入XML文件成功\n");elseprintf("写入XML文件失败\n");IXMLDOMDocument_Release(xmldoc);}
}int main()
{CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型create_xml("myxmlfile.xml");CoUninitialize();return 0;
}
第五节 创建XML字符串(使用char[]字符数组)
使用IXMLDOMNode_get_xml函数获取的是单个节点的XML字符串(不包括XML头部声明)。使用IXMLDOMDocument_get_xml函数可获取整个XML文档的字符串(包括XML头部声明)。
两个函数获取到的都是UTF-16编码的BSTR字符串,可使用convert_bstr_to_string函数转换成GB2312编码的char *字符串。
void write_xml(IXMLDOMDocument *xmldoc)
{IXMLDOMElement *root;create_header(xmldoc);root = create_root(xmldoc);add_post(xmldoc, root, "配置“Debug|Win32”", "将平台工具集更改为“v143”(之前为“v100”)。");add_post(xmldoc, root, "配置“Debug|x64”", "将平台工具集更改为“v143”(之前为“v100”)。");add_post(xmldoc, root, "配置“Release|Win32”", "将平台工具集更改为“v143”(之前为“v100”)。");add_post(xmldoc, root, "配置“Release|x64”", "将平台工具集更改为“v143”(之前为“v100”)。");add_post(xmldoc, root, "正在升级项目“xmltest”...", "重定目标结束: 1 个已完成,0 个未通过,0 个已跳过");IXMLDOMElement_Release(root);
}// 创建XML字符串
void create_xml_str()
{char *xmlstr;BSTR bstr;HRESULT hr;IXMLDOMDocument *xmldoc;hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, &xmldoc);if (SUCCEEDED(hr)){write_xml(xmldoc);IXMLDOMDocument_get_xml(xmldoc, &bstr);xmlstr = convert_bstr_to_string(bstr);SysFreeString(bstr);printf("%s\n", xmlstr);free(xmlstr);IXMLDOMDocument_Release(xmldoc);}
}int main()
{CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); // 初始化COM组件对象模型create_xml_str();CoUninitialize();return 0;
}
相关文章:

C语言通过MSXML6.0读写XML文件(同时支持char[]和wchar_t[]字符数组)
开发环境:Visual Studio 2010 运行环境:Windows XP SP3 第一节 读取XML文件(使用wchar_t[]字符数组) 读取XML文件可使用IXMLDOMDocument_load函数。 /* 这个程序只能在C编译器下编译成功, 请确保源文件的扩展名为c */ #define …...
在react中说说对受控组件和非受控组件的理解?以及应用场景
在react中说说对受控组件和非受控组件的理解?以及应用场景 回答思路:说说受控组件-->说说非受控组件-->应用场景受控组件:非受控组件应用场景 回答思路:说说受控组件–>说说非受控组件–>应用场景 受控组件ÿ…...

【算法练习Day50】下一个更大元素II接雨水
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 下一个更大元素II接雨水单调…...

深耕文档型数据库12载,SequoiaDB再开源
1月15日,巨杉数据库举行SequoiaDB新特性及开源项目发布活动。本次活动回顾了巨杉数据库深耕JSON文档型数据库12年的发展历程与技术演进,全面解读了SequoiaDB包括在高可用、安全、实时、易用性四个方向的技术特性,宣布了2024年面向技术社区的开…...
json解析
1什么是json JSON(JavaScript Object Notation,JS对象简谱)是一种轻量级的数据交换格式。它是基于ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰…...
【AI】深度学习在编码中的应用(8)
接上文,本文来梳理和学习智能编码中, 基于残差编码的框架。 智能图像编解码器的成功也推动了智能视频编解码器的发展。传统的视频压缩方法依靠预测编码对运动信息和残差信息分别进行编码。根据时-空域冗余消除方式和阶段不同,现有相关方法可…...

什么是VUE 创建第一个VUE实例
一、什么是Vue 概念:Vue (读音 /vjuː/,类似于 view) 是一套 构建用户界面 的 渐进式 框架 Vue2官网:Vue.js 1.什么是构建用户界面 基于数据渲染出用户可以看到的界面 2.什么是渐进式 所谓渐进式就是循序渐进,不一定非得把Vu…...

进程间协同:从进程启动、同步与互斥到进程间通信
进程间协同的目的 在操作系统中,进程是计算机进行任务分配和调度的基本单位。在计算机系统中,有很多任务是无法由单个进程独立完成的,需要多个进程共同参与并协作完成。这就像在现实生活中,有些工作需要一个团队来完成࿰…...

【驱动】TI AM437x(内核调试-06):网卡(PHY和MAC)、七层OSI
1、网络基础知识 1.1 七层OSI 第一层:物理层。 1)需求: 两个电脑之间如何进行通信? 具体就是一台发比特流,另一台能够收到。于是就有了物理层:主要是定义设备标准,如网线的额接口类型、管线的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流,就是从1/0…...

Java基础面试题 Object
Java基础面试题 Object 文章目录 Java基础面试题 ObjectObjectObject 类的常见方法有哪些? 和 equals() 的区别hashCode() 有什么用?为什么要有 hashCode?为什么重写 equals() 时必须重写 hashCode() 方法? 文章来自Java Guide 用…...
5G_射频测试_接收机测量(五)
7.2 Reference sensitivity level 接收灵敏度是表示接收机能解析出信号的最小功率(和接收机noise figure相关所以RX lineup的大部分工作就是在调整Gain达到最佳NF)The throughput shall be ≥ 95%(BER:bit error rate 并不是L3ca…...

ESP32-HTTP_webServer库(Arduino)
ESP32-HTTP 介绍 ESP32是一款功能强大的微控制器,具有丰富的网络和通信功能。其中之一就是支持HTTP协议,这使得ESP32可以用于创建Web服务器。 HTTP是什么? HTTP(Hyper Text Transfer Protocol),即超文本传…...

无法找到mfc100.dll的解决方法分享,如何快速修复mfc100.dll文件
在日常使用电脑时,我们可能会碰到一些系统错误提示,比如“无法找到mfc100.dll”的信息。这种错误通常会阻碍代码的执行或某些应用程序的启动。为了帮助您解决这一问题,本文将深入探讨其成因,并提供几种不同的mfc100.dll解决方案。…...
[VulnHub靶机渗透]:billu_b0x 快速通关
🍬 博主介绍👨🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏 == 养成习惯(一键三连)😋 🎉欢迎关注💗一起学习👍一起讨论⭐️一起进步…...

Docker安装开源Blog(Typecho)
前言 首先这个镜像是centos7.9进行安装PHP环境,然后挂载目录去运行的,镜像大概300MB左右,没学过PHP,没办法给Dockerfile文件 参考文章:Docker安装Typecho | D-y Blog感知不强,图一乐https://www.wlul.top…...

【Qt-license】误操作qt下载导致只能安装商业版试用十天,无法安装社区版
背景: 原本是为了学习qml,需要下载一个design studio,而这个需要比较新版的安装程序,但新版的安装程序官方都是online安装。于是从官网找下载链接。毕竟是英文的,又心急,误打误撞中我选择了商业版试用。 其…...

数据操作——缺失值处理
缺失值处理 缺失值的处理思路 如果想探究如何处理无效值, 首先要知道无效值从哪来, 从而分析可能产生的无效值有哪些类型, 在分别去看如何处理无效值 什么是缺失值 一个值本身的含义是这个值不存在则称之为缺失值, 也就是说这个值本身代表着缺失, 或者这个值本身无意义, 比如…...

【刷题笔记4】
动态规划题目汇总 斐波那契数列:1,1,2,3,5,8,13…… 递归一把解决三类问题:1.数据定义是按照递归的(斐波那契数列)。2.问题解法是按递归算法实现的。 3.数据…...

cuda二进制文件中到底有些什么
大家好。今天我们来讨论一下,相比gcc编译器编译的二进制elf文件,包含有 cuda kernel 的源文件编译出来的 elf 文件有什么不同呢? 之前研究过一点 tvm。从 BYOC 的框架中可以得知,前端将模型 partition 成 host 和 accel(accel 表…...

怎么从视频中提取动图?一个方法快速提取gif
视频以连续的方式播放一系列图像帧,通过每秒播放的帧数(帧率)来创做,由于GIF动图则以循环播放一系列静态图像帧的方式展现动画效果。由于视频的优势在于流畅的动画、丰富的细节和长时间播放,因此常用于电影、电视节目、…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...