需求:
使用xerces-c2.8的原因是, 这个版本是xerces-c 支持vc6IDE最后一个版本,再以前的版本官网上已经没有下载点了.
实际工程已经成型, 再升级到vs2008存在风险, 因为此工程中依赖的其他工程也是vc6IDE编译的.
基于xerces-c2.8,封装一个dll, 使通用的xml读写更方便.
<2011_0208_2340>
封装了基于xerces-c2.8的应用类, 实现了xmlBuffer的构造分析. 遗留的问题: 在xml头上有一段开始标记, 没有能添上字符集标志, 现在的Buffer分析都是约定好的, 不需要指定字符集. 如果是弄的标准些,那还是要添上。
现在是: <?xml version="1.0"?>
标准的是: <?xml version="1.0" encoding="GBK" ?>
以后再研究这个问题.
暂时只能封装成这样了.
/*****************************************************************************/ <2011_0301_1215><home><LostSpeed><XmlParserBaseOnXerces-c2.8 V1.0.0.1> * 迁移 Mukit-Ataul 的TXMLParserXerces, 修改了编译不过的地方(增加了XC, CX宏), 编译通过. 在类内部直接连接xerces-c_2.lib, 去掉了warning C4541. * 增加了接口 errno_t TXMLParserXerces::OpenDocument (TCHAR* buf, unsigned int len) 使直接操作流成为可能, 直接操作流是实际应用中最常见的. 特别是有些XML要求不能落地, 必须在内存操作. * 增加了针对xml流的构造和分析函数, * 增加了新的数据类框架, 使从xml返回的数据更容易管理. /*****************************************************************************/
调用端代码(构造xmlBuffer, 分析xmlBuffer)
void CMainiDlg::OnBUTTONFormXml() { PTCHAR pcXmlBuf = NULL; UINT uLen = 0; CLsXmlOperationLayer * pXml = new CLsXmlOperationLayer; if(S_OK == pXml->FormXml_Function_x(pcXmlBuf, uLen)) { //应用构造xml后的结果 pXml->WirteFile("c://tmp//FormXmlContent.xml", (PBYTE)pcXmlBuf, uLen); if(pcXmlBuf) { delete pcXmlBuf; pcXmlBuf = NULL; } } delete pXml; pXml = NULL; } void CMainiDlg::OnBUTTONParseXml() { UINT uLen = 0; PBYTE pcXmlBuf = NULL; CLsXmlOperationLayer * pXml = new CLsXmlOperationLayer; if(S_OK != pXml->ReadFile("c://tmp//FormXmlContent.xml", pcXmlBuf, uLen)) return; if(S_OK == pXml->ParseXml_Function_x(pcXmlBuf, uLen, pXml->m_XmlData_FileDecrypt)) { /** * 显示读回的xml数据, 在实际应用中, 就可以使用m_XmlData_FileDecrypt的数据了 */ pXml->m_XmlData_FileDecrypt.vDump(); /** * @note run results m_n64Version = 0x2011020417290001 m_pcBrief = 方便的数据类封装 m_csDataFileName = D:/LsPrj/subjectResearch/XmlParserBaseOnXerces-c2.8/bin/DataWarpper.dat m_strAlgID = CALG_RC4 m_strContainer = enccontainer m_strProvider = HaiTai Cryptographic Service Provider m_n64Version = 0x2011020417290001 m_pcBrief = 方便的数据类封装 m_csDataFileName = D:/LsPrj/subjectResearch/XmlParserBaseOnXerces-c2.8/bin/DataWarpper.dat m_strSrc = c:/tmp/test1.dat m_strDst = c:/tmp/test1.doc m_strSize = 26737 m_strSha1 = 147FD045B05DF28020896136B4F3602CB34B1D96 m_n64Version = 0x2011020417290001 m_pcBrief = 方便的数据类封装 m_csDataFileName = D:/LsPrj/subjectResearch/XmlParserBaseOnXerces-c2.8/bin/DataWarpper.dat m_strSrc = c:/tmp/test2.dat m_strDst = c:/tmp/test2.txt m_strSize = 65432 m_strSha1 = 247FD055B05DF28020896136B4F3602CB34B1D67 */ /** * 验证通过, 从xml读出的结果和构造的xml结果相同 */ } delete pcXmlBuf; pcXmlBuf = NULL; delete pXml; pXml = NULL; }
封装的xml业务层代码
// LsXmlOperationLayer.h: interface for the CLsXmlOperationLayer class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_LSXMLOPERATIONLAYER_H__155E2290_22B7_4941_8412_89A4CE5CFD73__INCLUDED_) #define AFX_LSXMLOPERATIONLAYER_H__155E2290_22B7_4941_8412_89A4CE5CFD73__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "LsXMLParserXerces.h" #include "DataClass_XmlNode_FileDecrypt.h" /**< Xml读回的数据放到这个数据结构里 */ //XML业务层 class CLsXmlOperationLayer { public: CLsXmlOperationLayer(); virtual ~CLsXmlOperationLayer(); //针对具体应用的的XML构造 SCODE FormXml_Function_x(PTCHAR &pcXmlBuf, UINT &uLen);//构造xml_用途1, 构造其他用途的xml参照这个函数 //针对具体应用的的XML分析 SCODE ParseXml_Function_x(BYTE *& pcXmlBuf, UINT &uLen, CDataClass_XmlNode_FileDecrypt & DataFileDecrypt);//分析xml_用途1, 分析其他用途的xml参照这个函数 BOOL GetNode_FileDecrypt( CDataClass_XmlNode_FileDecrypt &XmlData_FileDecrypt, TXMLParser* pParser, TXMLNode &NodeFileDescrypt); BOOL GetNode_File( CDataClass_XmlNode_FileDecrypt &XmlData_FileDecrypt, TXMLParser* pParser, TXMLNode &NodeFile); SCODE WirteFile(PTCHAR pcFileName, PBYTE pBuf, UINT uLen); /** * @name ReadFile * @brief 给出空指针pBuf, 读出文件内容到pBuf, 文件长度到uLen, * 由调用者释放pBuf * @param PTCHAR pcFileName, 要读取内容的文件名全路径 * @param PBYTE &pBuf, 给定的是空指针, 返回的是函数内部开辟的空间 * 由调用者负责释放 * @param UINT &uLen, 返回的文件长度 * @return SCODE * @retval S_OK, 成功 * @retval S_FALSE, 失败 */ SCODE ReadFile(PTCHAR pcFileName, BYTE *& pBuf, UINT &uLen); private: /** * 工具函数 */ BOOL stringIsSame(PCHAR pcLhs, PCHAR pcRhs); private: CLsXMLParserXerces * m_Parser; public: CDataClass_XmlNode_FileDecrypt m_XmlData_FileDecrypt; }; #endif // !defined(AFX_LSXMLOPERATIONLAYER_H__155E2290_22B7_4941_8412_89A4CE5CFD73__INCLUDED_)
// LsXmlOperationLayer.cpp: implementation of the CLsXmlOperationLayer class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "FrameworkOfXtremeDlg.h" #include "LsXmlOperationLayer.h" #include "TXMLParser.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CLsXmlOperationLayer::CLsXmlOperationLayer() { m_Parser = new CLsXMLParserXerces; } CLsXmlOperationLayer::~CLsXmlOperationLayer() { if(m_Parser) { delete m_Parser; m_Parser = NULL; } } SCODE CLsXmlOperationLayer::WirteFile(PTCHAR pcFileName, PBYTE pBuf, UINT uLen) { CFile file; if(file.Open(pcFileName, CFile::typeBinary | CFile::modeCreate | CFile::modeWrite)) { file.Write(pBuf, uLen); file.Close(); return S_OK; } return S_FALSE; } SCODE CLsXmlOperationLayer::ReadFile(PTCHAR pcFileName, BYTE *& pBuf, UINT &uLen) { CFile file; if(file.Open(pcFileName, CFile::typeBinary | CFile::modeRead)) { uLen = file.GetLength(); pBuf = new BYTE[uLen + 1]; *(pBuf + uLen) = '/0'; file.Read(pBuf, uLen); file.Close(); return S_OK; } return S_FALSE; } BOOL CLsXmlOperationLayer::stringIsSame(PCHAR pcLhs, PCHAR pcRhs) { if(!pcLhs && !pcRhs) return TRUE; if(!pcLhs || !pcRhs) return FALSE; return (0 == strcmp(pcLhs, pcRhs)) ? TRUE : FALSE; } SCODE CLsXmlOperationLayer::FormXml_Function_x(PTCHAR &pcXmlBuf, UINT &uLen) {//构造xml_用途1, 构造其他用途的xml参照这个函数 /** 假设我们要构造的xml如下所示, 有节点, 节点有属性值, 目标节点有值 节点有多个平行子节点 假设用途是指定一个命令行参数给一个MDI程序(xxSoft)一次性打开多个文件 <OrderToXxProgram> <FileDecrypt Provider="HaiTai Cryptographic Service Provider" Container="enccontainer" AlgID="CALG_RC4"> <file src="c://tmp//test1.dat" mce_src="c://tmp//test1.dat" dst="c://tmp//test1.txt"> <size>26737</size> <sha1>147FD045B05DF28020896136B4F3602CB34B1D96</sha1> </file> <file src="c://tmp//test2.dat" mce_src="c://tmp//test2.dat" dst="c://tmp//test2.doc"> <size>65432</size> <sha1>247FD055B05DF28020896136B4F3602CB34B1D67</sha1> </file> </FileDecrypt> </OrderToXxProgram> */ TXMLRoot NodeRoot;//根节点 OrderToXxProgram TXMLNode* pNodeChild1 = NULL;//1级节点 FileDecrypt TXMLNode* pNodeChild2 = NULL;//2级节点 file TXMLNode* pNodeChild3 = NULL;//3级节点 size, sha1 TXMLAttrib* pAttrib = NULL; TXMLParser* pParser = m_Parser->GetXmlPaser(); pParser->RemoveRoot(); //XML是单根树, 根节点不能有节点值和属性值 //设置字符集 pParser->SetCodePage("GBK"); //添加根节点, 设置根节点(名称, 值) m_Parser->AddRootNode(pParser, &NodeRoot, "OrderToXxProgram", ""); //设置根节点属性(名称, 值), 如果有多个属性, 重复下面1句代码 m_Parser->AddRootNodeAttrib(pParser, &NodeRoot, "", ""); //建立1级节点, 设置节点(名称, 值), 挂到根节点 pNodeChild1 = m_Parser->CreateNode(pParser); m_Parser->SetNode(pNodeChild1, "FileDecrypt", ""); m_Parser->MountNodeToNode(pParser, pNodeChild1, &NodeRoot); //建立属性,设置属性(名称, 值), 挂到1级节点 //如果有多个属性, 重复以下3句代码 pParser->DumpNodeVector(); pAttrib = m_Parser->CreateAttrib(pParser); pParser->DumpNodeVector(); m_Parser->SetAttrib(pAttrib, "Provider", "HaiTai Cryptographic Service Provider"); pParser->DumpNodeVector(); m_Parser->MountAttribToNode(pParser, pAttrib, pNodeChild1); pParser->DumpNodeVector(); //pParser->RemoveAttrib(pNodeChild1, "Provider");//好使 pAttrib = m_Parser->CreateAttrib(pParser); m_Parser->SetAttrib(pAttrib, "Container", "enccontainer"); m_Parser->MountAttribToNode(pParser, pAttrib, pNodeChild1); pAttrib = m_Parser->CreateAttrib(pParser); m_Parser->SetAttrib(pAttrib, "AlgID", "CALG_RC4"); m_Parser->MountAttribToNode(pParser, pAttrib, pNodeChild1); //---------------------------------------- //建立2级节点, 设置节点(名称, 值), 挂到1级节点 //---------------------------------------- pNodeChild2 = m_Parser->CreateNode(pParser); m_Parser->SetNode(pNodeChild2, "file", ""); m_Parser->MountNodeToNode(pParser, pNodeChild2, pNodeChild1); //建立属性,设置属性(名称, 值), 挂到2级节点 //如果有多个属性, 重复以下3句代码 pAttrib = m_Parser->CreateAttrib(pParser); m_Parser->SetAttrib(pAttrib, "src", "c://tmp//test1.dat"); m_Parser->MountAttribToNode(pParser, pAttrib, pNodeChild2); pAttrib = m_Parser->CreateAttrib(pParser); m_Parser->SetAttrib(pAttrib, "dst", "c://tmp//test1.doc"); m_Parser->MountAttribToNode(pParser, pAttrib, pNodeChild2); //建立3级节点, 设置节点(名称, 值), 挂到2级节点 pNodeChild3 = m_Parser->CreateNode(pParser); m_Parser->SetNode(pNodeChild3, "size", "26737"); m_Parser->MountNodeToNode(pParser, pNodeChild3, pNodeChild2); pNodeChild3 = m_Parser->CreateNode(pParser); m_Parser->SetNode(pNodeChild3, "sha1", "147FD045B05DF28020896136B4F3602CB34B1D96"); m_Parser->MountNodeToNode(pParser, pNodeChild3, pNodeChild2); //---------------------------------------- //建立2级节点, 设置节点(名称, 值), 挂到1级节点 //---------------------------------------- pNodeChild2 = m_Parser->CreateNode(pParser); m_Parser->SetNode(pNodeChild2, "file", ""); m_Parser->MountNodeToNode(pParser, pNodeChild2, pNodeChild1); //建立属性,设置属性(名称, 值), 挂到2级节点 //如果有多个属性, 重复以下3句代码 pAttrib = m_Parser->CreateAttrib(pParser); m_Parser->SetAttrib(pAttrib, "src", "c://tmp//test2.dat"); m_Parser->MountAttribToNode(pParser, pAttrib, pNodeChild2); pAttrib = m_Parser->CreateAttrib(pParser); m_Parser->SetAttrib(pAttrib, "dst", "c://tmp//test2.txt"); m_Parser->MountAttribToNode(pParser, pAttrib, pNodeChild2); //建立3级节点, 设置节点(名称, 值), 挂到2级节点 pNodeChild3 = m_Parser->CreateNode(pParser); m_Parser->SetNode(pNodeChild3, "size", "65432"); m_Parser->MountNodeToNode(pParser, pNodeChild3, pNodeChild2); pNodeChild3 = m_Parser->CreateNode(pParser); m_Parser->SetNode(pNodeChild3, "sha1", "247FD055B05DF28020896136B4F3602CB34B1D67"); m_Parser->MountNodeToNode(pParser, pNodeChild3, pNodeChild2); //保存Xml内容到Buffer, 传给调用者 return m_Parser->SaveToStream(pParser, pcXmlBuf, uLen); } SCODE CLsXmlOperationLayer::ParseXml_Function_x (BYTE *& pcXmlBuf, UINT &uLen, CDataClass_XmlNode_FileDecrypt & DataFileDecrypt) {//分析xml_用途1, 分析其他用途的xml参照这个函数 /** * 这里分析由FormXml_Function_x构造的XML, * 把得到的内容放到数据类中m_XmlData_FileDecrypt */ int n = 0; BOOL bFind = FALSE; int nCntNode1 = 0;//1级节点数量 TXMLRoot NodeRoot;//根节点 OrderToXxProgram TXMLNode NodeChild1;//1级节点 FileDecrypt TXMLParser* pParser = m_Parser->GetXmlPaser(); if(!m_Parser->OPenXML((PCHAR)pcXmlBuf, uLen)) return S_FALSE; if(TXMLParser::NO_XML_ERROR != pParser->GetRoot(NodeRoot)) return S_FALSE; //寻找根节点<OrderToXxProgram> if(!stringIsSame("OrderToXxProgram", (PCHAR)NodeRoot.GetName())) return S_FALSE; //根节点<OrderToXxProgram>必须有1个以上的子节点, 其中包含<FileDecrypt>节点 nCntNode1 = pParser->GetChildCount(&NodeRoot); if(nCntNode1 <= 0) return S_FALSE; //寻找一级节点<FileDecrypt> bFind = FALSE; for(n = 0; n < nCntNode1; n++) { if(!pParser->GetChild(n, &NodeRoot, NodeChild1)) return S_FALSE; if(stringIsSame("FileDecrypt", (PCHAR)NodeChild1.GetName())) { bFind = TRUE; break; } } if(!bFind) return S_FALSE; if(!GetNode_FileDecrypt(DataFileDecrypt, pParser, NodeChild1)) return FALSE; return S_OK; } BOOL CLsXmlOperationLayer::GetNode_FileDecrypt( CDataClass_XmlNode_FileDecrypt &XmlData_FileDecrypt, TXMLParser* pParser, TXMLNode &NodeFileDecrypt) { int n = 0; int nCntNode2 = 0;//2级节点数量 int nCntAttrib = 0; int nCntFindAttrib = 0; TXMLAttrib Attrib; PTCHAR pAttribName = NULL; TXMLRoot NodeRoot;//根节点 OrderToXxProgram TXMLNode NodeChild2;//2级节点 file //<FileDecrypt>节点包含3个属性<Provider, Container, AlgID> nCntAttrib = pParser->GetAttribCount(&NodeFileDecrypt); if(nCntAttrib < 3) return S_FALSE; nCntFindAttrib = 0; for(n = 0; n < nCntAttrib; n++) { if(!pParser->GetAttrib(n, &NodeFileDecrypt, Attrib)) return FALSE; pAttribName = (PCHAR)Attrib.GetName(); if(pAttribName) { if(stringIsSame("Provider", pAttribName)) { XmlData_FileDecrypt.m_strProvider = Attrib.GetValueString(); nCntFindAttrib++; } else if(stringIsSame("Container", pAttribName)) { XmlData_FileDecrypt.m_strContainer = Attrib.GetValueString(); nCntFindAttrib++; } else if(stringIsSame("AlgID", pAttribName)) { XmlData_FileDecrypt.m_strAlgID = Attrib.GetValueString(); nCntFindAttrib++; } } } if(nCntFindAttrib < 3) return S_FALSE; /** * 寻找一级节点<FileDecrypt>下的<file>节点 * 可能有多个平行的file节点 */ nCntNode2 = pParser->GetChildCount(&NodeFileDecrypt); for(n = 0; n < nCntNode2; n++) { if(pParser->GetChild(n, &NodeFileDecrypt, NodeChild2)) { if(stringIsSame("file", (PCHAR)NodeChild2.GetName())) { GetNode_File(XmlData_FileDecrypt, pParser, NodeChild2); } } } return TRUE; } BOOL CLsXmlOperationLayer::GetNode_File( CDataClass_XmlNode_FileDecrypt &XmlData_FileDecrypt, TXMLParser* pParser, TXMLNode &NodeFile) { BOOL bFind = FALSE; int n = 0; int nCntNode = 0; int nCntAttrib = 0; int nCntFindAttrib = 0; int nCntFindNode = 0; TXMLAttrib Node; PTCHAR pNodeName = NULL; TXMLAttrib Attrib; PTCHAR pAttribName = NULL; CDataClass_XmlNode_file * pDataNodeFile = new CDataClass_XmlNode_file; try { /** * <file>节点有2个属性<src, dst> */ nCntAttrib = pParser->GetAttribCount(&NodeFile); if(nCntAttrib < 2) throw((DWORD)(-1)); nCntFindAttrib = 0; for(n = 0; n < nCntAttrib; n++) { if(!pParser->GetAttrib(n, &NodeFile, Attrib)) throw((DWORD)(-1)); pAttribName = (PCHAR)Attrib.GetName(); if(pAttribName) { if(stringIsSame("src", pAttribName)) { pDataNodeFile->m_strSrc = Attrib.GetValueString(); nCntFindAttrib++; } else if(stringIsSame("dst", pAttribName)) { pDataNodeFile->m_strDst = Attrib.GetValueString(); nCntFindAttrib++; } } } if(2 != nCntFindAttrib) throw((DWORD)(-1)); /** * 寻找子节点<size, sha1> */ nCntNode = pParser->GetChildCount(&NodeFile); if(nCntAttrib < 2) throw((DWORD)(-1)); nCntFindNode = 0; for(n = 0; n < nCntAttrib; n++) { if(!pParser->GetChild(n, &NodeFile, Node)) throw((DWORD)(-1)); pNodeName = (PCHAR)Node.GetName(); if(pNodeName) { if(stringIsSame("size", pNodeName)) { pDataNodeFile->m_strSize = Node.GetValueString(); nCntFindNode++; } else if(stringIsSame("sha1", pNodeName)) { pDataNodeFile->m_strSha1 = Node.GetValueString(); nCntFindNode++; } } } if(2 != nCntFindNode) throw((DWORD)(-1)); } catch (DWORD dwe) { UNREFERENCED_PARAMETER(dwe); if(pDataNodeFile) { delete pDataNodeFile; pDataNodeFile = NULL; } return FALSE; } XmlData_FileDecrypt.m_vecNodeFile.push_back(pDataNodeFile); return TRUE; }
这次提炼出的TXMLParserXerces有个优点, 把具体的实现层给封装了,替代为TXMLNode这种封装的类. 使调用端代码和业务层代码保持不变的情况下,直接更换TXMLParserXerces, 就可以更换另外的xml分析器.
工程下载点:
http://download.csdn.net/source/3014001
srcXmlParserBaseOnXerces-c2.8_V2011_0209_0011
可以借鉴到别的应用上,比如数据库应用.
<2011_0212>
找到了加xml头和编码信息的方法
/** * 添加xml头和编码类型 * 原来这里是直接手工添加的! * <?xml version="1.0" encoding="GBK" ?> */ //const TCHAR xmlBanner[] = _T("<?xml version=/"1.0/"?>/n"); const TCHAR xmlBanner[] = _T("<?xml version=/"1.0/" encoding=/"GBK/" ?>/n");
<2011_0212_1657>
xerces-c所有版本的下载总目录:
http://archive.apache.org/dist/xml/xerces-c/
xerces-c最新版本的下载总目录:
http://apache.etoak.com//xerces/
原因: 现有成型工程是xerces-c2.7静态库, 我新加入的功能用的是xerces-c2.8动态库. lib的名称都是xerces-c_2.lib, 但是名字空间不同。更换了xerces-c_2.lib后,导致2.7版的名字空间内的都找不到了. 现在要找到一种方法,xerces-c的应用正常运行.
1. 使2.7版和2.8版在一起运行,重新编译2.7版, 打开RTTI. 实验确定2.7和2.8版的兼容性.
实验方法: 编译2.7版静态库, 做一个使用2.7版静态库的程序, 再加入使用2.8版动态库的功能,不兼容的地方在取节点属性计数的时候。
通过实验来调整, 如果是2.7RTTI的问题.那就把2.7版RTTI关闭,和实际工程一样。继续调整,使之兼容.
2. 全部使用2.7版静态库, 这个要看新版的功能正常么?
3. 把2.8版功能全部封到一个独立的DLL里面, 形成一个XML业务层DLL.
<2011_0213>
实验确定: 是实际工程中xerces-c2.7静态库编译时没有打开RTTI选项, 导致我现有的代码不能正常运行.实际工程中的静态库在现有工程中广泛使用, 不可能去再编译了. 我现有的2.8版代码在2.8版dll下面运行正常,我也不想去改了.
我把2.8版DLL的引入库给在编译时改名了, 这样, 在编译的时候,和2.7版的lib名字就不同.
现在要编译一个2.7的静态库, 通过实验看看,怎么能使2.7静态库和2.8版动态库的调用能兼容, 我觉得悬. 因为头文件名称都是相同的, 只有名字空间不同. 实在不行,就得封个DLL把2.8版功能封住了.
<2011_0215>
基于xercesc_2.8版的XML应用层DLL封装完毕.
工程下载点:
http://download.csdn.net/source/3022196
基于xerces-c2.8操作的XML业务层DLL V1.0.0.1
同事说工程中用的是xerces-c2.7静态库, 我下载了xerces-c2.7源码后编译。没有发现2.7版有静态库编译选项. 建立了一个空的静态库, 手工添加文件, 文件夹嵌套层数太多,看的眼晕, 放弃. 仔细看了下工程中的xerces-c_2.lib, 大小和动态库的引入库差不多. 而且exe同级目录中有xerces-c_2_7.dll和xerces-c_2_7D.dll. 由此断定工程中使用的也是xerces-c2.7动态库版本.
不喜欢用静态库, 复用性不强. 而且和主工程的运行时库不同的话, 还会编译不过,还得调整编译时的库顺序.
动态库封的好的话,复用性很强. 调用者包含的头文件除了通用头文件就是封装了通用头文件的普通类. 如果不导出类,做成标准的dll函数接口,那样更通用. 如果有很多dll接口函数名字相同, 可以用名字空间隔开.
<2011_0217>
使用中发现, 如果给定的xml流中有中文,必须在头上加入编码标记为GBK
/** * 构造XML时, 如果有中文内容, 需要加入 encoding=/"GBK/" * 否则装入流的时候过不去 */ CString strXmlOutCase1 = "<?xml version=/"1.0/" encoding=/"GBK/" ?>/n/ <response>/n/ <item>/n/ <property name=/"rights/">/n/ <value>中文内容不正常么1?</value>/n/ </property>/n/ </item>/n/ </response>"; //pcXmlBuf, uLen 从strXmlOutCase1来的 if(!m_pLsXmlOperationLayer->m_Parser->OPenXML((PCHAR)pcXmlBuf, uLen)) { /** * 构造XML时, 如果有中文内容, 需要加入 encoding=/"GBK/" * 否则装入流的时候过不去 */ return S_FALSE; }