首先声明:文章中的内容大都来源于网络,做的过程遇到了不少问题,所以想写下此文,记录一个完整的过程,以飨后人。
gsoap为何物,相信能看到这篇文章的人一定是有所了解了。不过还是啰嗦一下,保持文章的完整性。
gSOAP是一个夸平台的,用于开发Web Service服务端和客户端的工具,在Windows、Linux、MAC OS和UNIX下使用C和C++语言编码,集合了SSL功能。
下载地址:http://sourceforge.net/projects/gsoap2
官方网站:http://genivia.com/Products/gsoap/index.html
1、配置gSOAP
下载gSOAP,解压后在gsoap\bin\win32里找到wsdl2h.exe和soapcpp2.exe程序。通过这两个程序可以生成客户端需要的C/C++文件。这两个程序的使用方法:
wsdl2h.exe:
编译wsdl文件生成c/c++头文件
-o 文件名,指定输出头文件
-n 名空间前缀
代替默认的ns
-c 产生纯C代码,否则是C++代码
-s
不要使用STL代码
-t 文件名,指定type map文件,默认为typemap.dat
-e
禁止为enum成员加上名空间前缀
soapcpp2.exe:
gSOAP编译器,编译头文件生成服务器和客户端都需要的c/c++文件
(如果使用STL,需要从压缩包里找到stlvector.h放到soapcpp2.exe目录下,否则运行失败)
-C 仅生成客户端代码
-S
仅生成服务器端代码
-L 不要产生soapClientLib.c和soapServerLib.c文件
-c
产生纯C代码,否则是C++代码(与头文件有关)
-I 指定import路径(见上文)
-x
不要产生XML示例文件
-i
生成C++包装,客户端为xxxxProxy.h(.cpp),服务器端为xxxxService.h(.cpp)
写个批处理:
wsdl2h -o
xxxService.h "WSDL文件URL"
soapcpp2 -C xxxService.h
如果是asmx,可以在URL后加 "?WSDL"
来获取WSDL文件,它是一个XML,用来描述接口,它是与语言无关的,类似COM的IDL文件。
2、创建VC工程,把生成的文件拷到工程目录
生成的文件有:
soapStub.h 从输入 Header 文件生成的经过修改且带标注的 Header
文件
soapH.h 主 Header 文件,所有客户机和服务源代码都要将其包括在内
soapC.c 指定数据结构的序列化器和反序列化器
soapClient.c
远程操作的客户机存根例程
stdsoap2.h stdsoap2.cpp 运行时库的 Header 文件
stdsoap2.cpp
运行时 C++ 库,带 XML 解析器和运行时支持例程
为 soapC.c、soapClient.c 和 stdsoap2.cpp 选择 Not using precompiled headers,因为它们并不依赖于 stdafx.h。(生成.c或者.cpp由编译选项决定,.c是纯C代码,.cpp是c++的)

在vs2008中,如图所示,先选中文件,项目——属性,选择“不使用预编译头”。
3、调用Web服务:
调用web服务有两种方式,可以直接调用也可以使用代理
3.1直接调用
_ns1__Add add ; // 调用接口
_ns1__AddResponse addResponse ; // 用来接收返回值
double dx = 1, dy = 2, dResult = 0;
struct soap soap;
soap_init(&soap);
getContext.x = &dx ;
getContext.y = &dy;
double result = soap_call___ns1__Add(&soap,NULL,NULL,&add,&addResponse);
if(result == SOAP_OK)
{
dResult = *addResponse.AddResult;
}
else
soap_print_fault(&soap,stderr);
3.2使用代理
double dx = 1, dy = 2, dResult = 0;
_ns1__Add add;
_ns1__AddResponse addResponse ;
add.x = &dx;
add.y = &dy;
BasicHttpBinding_USCORECalculatorService q; //代理类
double result = q.__ns1__Add(&add,&addResponse);
if(result == SOAP_OK)
{
dResult = *addResponse.AddResult;
}
else
soap_print_fault(q.soap,stderr);
个人认为,使用代理会稍微方便一些,如果直接调用,上面的代码还不完整,需要调用 soap_destroy(&clientSOAP)、soap_end(soap)清除环境变量、soap_done(&clientSOAP),soap定义一次可以重复使用。至于soap初始化的其他方法,可以参照gsoap的文档,在文章最后我会给出gsoap中文文档的下载地址。
至此,简单的demo调用应该是可以了,不过总会有意想不到的事情发生
4、解决415错误:
这个是由于服务端客户端soap协议不统一造成的,我使用的gsoap是2.8.8版本,编译出来的xxx.nsmap中soap协议是1.2版本,连接的wcf服务是1.1版本。
目前这个问题有两个方法可以解决,1,手工修改nsmap文件中的协议,2,使用gsoap编译器“-1”编译选项(此方法未测试,据说有些时候也无效)
//手动修改namespace, 生成soap1.1.
struct Namespace namespaces[] =
{
{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", NULL, NULL},
{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", NULL, NULL},
{"xsi", "http://www.w3.org/2001/XMLSchema-instance", NULL, NULL},
{"xsd", "http://www.w3.org/2001/XMLSchema", NULL, NULL},
//{"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://www.w3.org/2003/05/soap-envelope", NULL},
//{"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://www.w3.org/2003/05/soap-encoding", NULL},
//{"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},
//{"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},
{"ns4", "http://schemas.datacontract.org/2004/07/SnailGame.Toolkits.MessageSendService", NULL, NULL},
{"ns3", "http://schemas.microsoft.com/2003/10/Serialization/", NULL, NULL},
{"ns1", "http://tempuri.org/", NULL, NULL},
{NULL, NULL, NULL, NULL}
};
5、解决中午乱码的问题:
通过上面的步骤,已经可以成功连接了,但是在遇到中文字符的时候,问题就出现了。
5.1中文字符返回值
这个解决的办法主要就是要把字符转换成utf-8
1>设置GSOAP的编码模式 soap_set_mode(soap, SOAP_C_UTFSTRING);
2>将传输回来的字符流进行字符转换
//ns5__SimpleNetObject是WCF中定义的结构体,返回值是此类型
//mapServiceResponse用来接收返回值,参看前面的addResponse就明白了 ns5__SimpleNetObject d = *mapServiceResponse.PublishMapServiceResult; std::wstring str; std::string stt = d.Message; //转换为utf-8编码 bool fl = WFromUTF8(reinterpret_cast<const char* >(stt.c_str()), str); CString s = str.c_str();
3>字符转换函数
#if !defined(TEXTCONVERT_H)
#define TEXTCONVERT_H
//多字节字符串转换为宽字节字符串
// CodePage:[in]编码
// lpcwszText:[in]多字节字符串
// lppszVal:[out]宽字节字符串
//返回值:TRUE表示成功,其它表示失败
inline BOOL WcharFromChar(UINT CodePage,const char *lpcszText,std::wstring &wstrVal)
{
WCHAR *lpwszVal( NULL );
int nLength(0);size_t dwSize(0);
nLength = ::MultiByteToWideChar( CodePage, 0, lpcszText, -1 , NULL, 0);
if( nLength <= 0 ) return FALSE;dwSize = nLength * sizeof(WCHAR);
lpwszVal = (WCHAR *)malloc( dwSize );
if( NULL == lpwszVal ) return FALSE;
memset(lpwszVal,0x0,dwSize);
nLength = ::MultiByteToWideChar( CodePage, 0, lpcszText, -1 , lpwszVal, nLength );
if( nLength <= 0 )
{
free(lpwszVal);
lpwszVal = NULL;
return FALSE;
}
wstrVal.assign( lpwszVal );
free(lpwszVal);
lpwszVal = NULL;
return TRUE;
}
//UTF-8字符串转换为宽字节字符串
// lpcwszText:[in]UTF-8字符串
// lppszVal:[out]宽字节字符串
//返回值:TRUE表示成功,其它表示失败
inline BOOL WFromUTF8(const char *lpcszText,std::wstring &wstrVal )
{
return WcharFromChar(CP_UTF8,lpcszText,wstrVal);
}
#endif
5.2中文字符参数
中文字符返回值的问题解决了,新的问题又出现了,如果按照上面的设置,如果是有中文字符的参数,这个参数就会乱码了,真是一波刚平一波又起啊。
有人提出了用setloacal的方法来解决,不过这个办法我使用的时候无效。
返回值乱码,我们是将其从转换成utf-8的编码方式,那么,我们传人的参数有问题,在传人参数之前,先将其转换成utf-8是不是就可以呢。(当前是unicode,大概等价于utf-16,未查证)
如果是linux系统,貌似有直接的装换函数,可惜我是在windows平台,那就自己写吧,有了上面的转换方法,照猫画虎,也就是那样。
//字符编码转换
std::string Convert(std::wstring str,int targetCodepage)
{
BYTE* pTargetData = NULL;
size_t souceLen=WideCharToMultiByte(targetCodepage,0,(LPWSTR)str.c_str(),-1,(char *)pTargetData,0,NULL,NULL);
pTargetData=new BYTE[souceLen+1];
memset(pTargetData,0,souceLen+1);
WideCharToMultiByte(targetCodepage,0,(LPWSTR)str.c_str(),-1,
(char*)pTargetData,souceLen,NULL,NULL);
std::string rt((char*)pTargetData);
delete [] pTargetData;
return rt;
}
调用方法
CString str = _T("测试中文");
std::wstring ss = str;
std::string var =Convert(ss,CP_UTF8);
行文至此,我所解决的问题也就是这么多了,目前也可以运行起来了,不过还是有几个小问题困扰着我
遇到的问题
1>在我的机子上wsdl工具无法生成头文件,gsoap工具正常,同样的工具,在我同事的机子上可以正常运行
2>WCF选择http协议没有问题,如果是TCP协议,就不能正常连接,不知是不是不支持
解决的问题
本文解决的问题,主要是C++语言对wcf服务的访问
c++访问wcf的3种方式
1,托管c++,缺点猜想,部署项目的时候需要包含.net库,讨厌这种拖泥带水的。
2,用c#访问WCF,重新包装一个接口,生成dll, 供c++使用;缺点,还是需要公共语言运行库支持,也即托管c++
3, 用gsoap
综合考虑,还是用gsoap比较好,而且我的程序是C/S结构的,客户端用c++编写,如果加入clr,部署起来会比较麻烦。
最后奉上两个下载链接,为了防止外链失效,我给一个博客园的下载地址
gSoap 2.8.8版本下载
gSoap 中文文档下载
很可惜,试了一下,我的上传权限单个文件只有1M,无法上传,有需要的留个邮箱吧,我看到了就发给你们。其实这些自己搜索也很容易找的。
参考文章:http://www.cppblog.com/qiujian5628/archive/2008/06/19/54019.html
http://hi.baidu.com/lbird/blog/item/0222bb6eb2eb12d480cb4a50.html
http://blog.csdn.net/zozoiiiiiiii/article/details/7418339
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/1ff173ee-c371-45b1-986b-fbb67ea94de8/
http://blog.sina.com.cn/s/blog_6a22547f0100v0wn.html
http://blog.csdn.net/spyy26224574/article/details/3340913
两天做的过程中,查看了很多人的文章,由于参看内容繁杂,在此未能一一列举,深表歉意。
在我的上一篇博文里面,谈到了注记的转换问题,但是其中的转换并未包含空间参考信息,所以,再写一篇来记录空间参考信息的转换。
首先,是获取dwg文件中的参考信息,部分关键代码如下
IWorkspacePtr ipWork;
IWorkspaceFactoryPtr ipWFactory(CLSID_CadWorkspaceFactory);
HRESULT result = ipWFactory->OpenFromFile(CComBSTR(path),
NULL, &ipWork);
IFeatureWorkspacePtr ipFWork = ipWork;
IFeatureDatasetPtr ipDataset;
result = ipFWork->OpenFeatureDataset(CComBSTR(filename), &ipDataset);
IFeatureClassContainerPtr ipFContainer = ipDataset;
IArrayPtr arrLayer(CLSID_Array);
long lClassCount = 0;
ipFContainer->get_ClassCount(&lClassCount);
for (long i = 0; i < lClassCount; i++)
{
IFeatureClassPtr ipFClass;
result = ipFContainer->get_Class(i, &ipFClass);
esriFeatureType type;
ipFClass->get_FeatureType(&type);
//判断是否为注记层
if (esriFTCoverageAnnotation != type)
continue;
IGeoDatasetPtr ipGeoDataset(ipFClass);
ISpatialReferencePtr ipSpaRef;
ipGeoDataset->get_SpatialReference(&ipSpaRef);
}
接下来,就是把获取到的空间参考信息设置到SDE中的annotation features中,可以通过IFeaturelayer,ILayer等接口来设置,由于比较简单,就不把代码贴出来了。如果大家有其他好的办法,也欢迎留言交流
CAD注记层转到SDE Annotation Features本文会提到两种方式,不过都是要添加一个element,所以,首先给出一个创建element的函数
ITextElementPtr MakeTextElement(CString strText, double x, double y)
{
HRESULT hr;
ITextElementPtr ipTextElement(CLSID_TextElement);
hr = ipTextElement->put_ScaleText(VARIANT_TRUE);
hr = ipTextElement->put_Text(CComBSTR(strText));
IGroupSymbolElementPtr ipGroupSymEle = ipTextElement;
ipGroupSymEle->put_SymbolID(0);
IPointPtr ipPoint(CLSID_Point);
ipPoint->put_X(x);
ipPoint->put_Y(y);
IElementPtr ipElement = ipTextElement;
ipElement->put_Geometry(ipPoint);
return ipTextElement;
}
第一种办法,通过IFDOGraphicsLayer添加Elements的方式实现,实现办法如下
BOOL AddTextElementEx(CString strText, double x, double y)
{
HRESULT hr;
IFeatureWorkspacePtr ipFeatWorkspace = m_ipWorkspace;
if(ipFeatWorkspace == NULL)
return FALSE;
IFeatureClassPtr ipFeatureClass;
hr = ipFeatWorkspace->OpenFeatureClass(CComBSTR(_T("abc")),&ipFeatureClass);
IWorkspaceEditPtr ipWorkspaceEdit = m_ipWorkspace;
if(ipWorkspaceEdit==NULL)
return FALSE;
IDatasetPtr ipDataset(ipFeatureClass);
IFDOGraphicsLayerFactoryPtr ipFDOGLFactory(CLSID_FDOGraphicsLayerFactory);
IWorkspacePtr ipWs;
ipDataset->get_Workspace(&ipWs);
IFeatureWorkspacePtr ipFeatWs(ipWs);
IFeatureDatasetPtr ipFeatDataset;
ipFeatureClass->get_FeatureDataset(&ipFeatDataset);
ILayerPtr ipLayer;
BSTR bstr;
hr = ipDataset->get_Name(&bstr);
hr = ipFDOGLFactory->OpenGraphicsLayer(ipFeatWs,ipFeatDataset,bstr,&ipLayer);
if(FAILED(hr))
return FALSE;IFDOGraphicsLayerPtr ipFDOGLayer(ipLayer);
IElementCollectionPtr ipElementColl;
hr = ipElementColl.CreateInstance(CLSID_ElementCollection);
if(FAILED(hr)||ipElementColl==NULL)
return FALSE;
ITextElementPtr ipTextElement = MakeTextElement(strText,x,y);
hr = ipElementColl->Add((IElementPtr)ipTextElement,-1);
hr = ipFDOGLayer->BeginAddElements();
hr = ipFDOGLayer->DoAddElements(ipElementColl,0);
hr = ipFDOGLayer->EndAddElements();
return TRUE;
}
第二种方式,通过IAnnotationFeature来实现,实现代码如下
BOOL AddTextElement(CString strText, double x, double y)
{
HRESULT hr;
IFeatureWorkspacePtr ipFeatWorkspace = m_ipWorkspace;
if(ipFeatWorkspace == NULL)
return FALSE;
IFeatureClassPtr ipFeatureClass;
hr = ipFeatWorkspace->OpenFeatureClass(CComBSTR(_T("abc")),&ipFeatureClass);
IWorkspaceEditPtr ipWorkspaceEdit = m_ipWorkspace;
if(ipWorkspaceEdit==NULL)
return FALSE;
hr = ipWorkspaceEdit->StartEditing(TRUE);
hr = ipWorkspaceEdit->StartEditOperation();
hr = ipWorkspaceEdit->EnableUndoRedo();
IElementPtr ipElement = MakeTextElement(strText,x , y);
IAnnotationFeaturePtr ipAnnotationFeature = ipFeature;
if(ipAnnotationFeature == NULL)
return FALSE;
hr=ipAnnotationFeature->put_Annotation(ipElement);
ipWorkspaceEdit->DisableUndoRedo();
ipWorkspaceEdit->StopEditOperation();
ipWorkspaceEdit->StopEditing(TRUE);
return TRUE;
}
这两种方法,经过实际测试都可以成功,在导入的时候还需要注意一下空间参考系的问题,需要对应上,特别要注意dwg中的数据是否正确,如果注记的坐标不在参考系范围内,会出现导入失败的现象,我就是因为这个低级的错误,纠结了两天。
参考资料:http://www.cnblogs.com/iswszheng/archive/2009/03/18/1415496.html
AE10中一个明显的改变就是运行时绑定,ArcGIS10有一些明显的产品架构上变更。新架构最明显的优势是独立存在的ArcGIS Desktop和Engine runtime。你可以将ArcGIS Desktop和Engine安装在不同的目录下。你同样可以分别为Engine和Desktop打补丁。但是这种构架的变化要求你将你的Engine程序以及自定义组件绑定到你机器上指定的产品。独立应用程序既可绑定到Desktop也可以绑定到Engine的runtime。但是,要在程序使用AO之前就做好绑定。
那么,应该如何绑定呢(C#实现)
首先添加引用:
ESRI.ArcGIS.Version
然后
ESRI.ArcGIS.RuntimeManager.Bind(ProductCode.Engine)
那么,绑定就结束了,是不是很简单啊。
其他的一些新增函数
RuntimeManager.BindLicense()
绑定运行时同时初始化许可
RuntimeManager.InstalledRuntimes
返回已安装的运行时
RuntimeManager.ActiveRuntime
返回当前已绑定的运行时
RuntimeInfo
获得路径、版本等信息
这些信息在网上很容易找到,那么,如果是用C++该如何实现呢
VARIANT_BOOL InitializeLicense(esriLicenseProductCode product)
{
IAoInitializePtr ipInit(CLSID_AoInitialize);
esriLicenseStatus licenseStatus = esriLicenseFailure;
ipInit->IsProductCodeAvailable(product, &licenseStatus);
if (licenseStatus == esriLicenseAvailable)
ipInit->Initialize(product, &licenseStatus);
return (licenseStatus == esriLicenseCheckedOut);
}
这是主要的代码,但是仅仅是这样,编译的时候就会出问题,所以在绑定前,还需要LoadVersion,在stdafx.h中添加如下代码
/* Version support */
#import "libid:6FCCEDE0-179D-4D12-B586-58C88D26CA78" no_namespace raw_interfaces_only no_implementation rename("esriProductCode", "esriVersionProductCode")
#define PRODUCTSTRING(ver) L"" L#ver
#define ESRI_SET_VERSION(prod,vers)
{
HRESULT hr;
VARIANT_BOOL vb;
CComBSTR bsVer(PRODUCTSTRING(vers));
IArcGISVersionPtr ipVersion(__uuidof(VersionManager));
if(!SUCCEEDED(hr = ipVersion->LoadVersion(prod, bsVer, &vb)))
fprintf(stderr, "LoadVersion() failed with code 0x%.8x\n", hr);
else if(vb != VARIANT_TRUE)
fprintf(stderr, "LoadVersion() failed\n");
}
在InitInstance()中最开始,就调用
::CoInitialize(NULL);
ESRI_SET_VERSION(esriArcGISEngine, 10.0)
InitializeLicense(esriLicenseProductCodeEngine);
至此,已经完成许可初始化与运行时绑定。
参考资料:
http://help.arcgis.com/EN/sdk/10.0/ArcObjects_NET/conceptualhelp/index.html#//000100000nmm000000
http://hi.baidu.com/o%B3%A3%BD%F8/blog/item/eb9e590dc04a7d0a95ca6ba8.html
环境:Xtreme.Toolkit.Pro v11.2.1+vs2008sp1
在工作中用到了CXTPCommandBars,但是按照默认的,是英文的,这样拿给客户,肯定是不行的,所以需要改成中文。我想着改一下资源文件里面的内容(我理解就是改一下宏)。这样改了以后,发现中文会出现乱码。然后我设想设置一下setlocale,但是,事实证明,我这个拍脑袋的想法行不通。最后,认真查看了资料,发现其实Xtreme本身就提供了多语言的支持,不需要自己改资源文件,已经有现成的资源文件了。
现在,开始我们的汉化。
一、打开ToolkitPro_vc90.sln项目,然后查看ToolkitPro.rc源代码,拉到文件最后,会发现如下的定义:
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)
#endif //_WIN32
#include "XTToolkitPro.rc" // non-Microsoft Visual C++ edited resources
#include "afxres.rc" // Standard components
#endif
代码中定义包含的文件"XTToolkitPro.rc" 是在Toolkit.Pro的Source文件夹下的,"XTToolkitPro.rc" 文件集中定义的是界面库各种控件的资源文件。
二、打开"XTToolkitPro.rc"文件,我们发现文件开头几行定义说明了一切问题。
#define LANGUAGE_DEFAULT(ProdName) <##ProdName##\res\Resource.rc>
#ifdef _XTP_RESOURCE_LANGUAGE
#define LANGUAGE_LOCALIZED__(ProdName, LangName) <##ProdName##\res\Resource_##LangName##.rc>
#define LANGUAGE_LOCALIZED_(ProdName, LangName) LANGUAGE_LOCALIZED__(ProdName, LangName)
#define LANGUAGE_LOCALIZED(ProdName) LANGUAGE_LOCALIZED_(ProdName, _XTP_RESOURCE_LANGUAGE)
#else
#define LANGUAGE_LOCALIZED(ProdName) LANGUAGE_DEFAULT(ProdName)
#endif
#define LANGUAGE_DEFAULT(ProdName) <##ProdName##\res\Resource.rc> 定义了缺省的语言
#ifdef _XTP_RESOURCE_LANGUAGE
定义的标识_XTP_RESOURCE_LANGUAGE可以看出定义的即是语言的标识。那么只要在程序库中定义该标识就可以使界面库应用相对应的语言资源库了。
三、打开Source文件下每个控件的文件夹下都可以看到许多后缀为.rc的资源文件

由资源文件的名称(Resource_zh_CN.rc),再由定义
#define LANGUAGE_LOCALIZED__(ProdName, LangName) <##ProdName##/res/Resource_##LangName##.rc>
可以很容易猜得到中文的定义为zh_CN,自然可知定义中文的语句即为:
#define _XTP_RESOURCE_LANGUAGE zh_CN
这个定义我习惯放在XTToolkitPro.rc文件的开头
#include "afxres.h"
#define _XTP_RESOURCE_LANGUAGE zh_CN
#define LANGUAGE_DEFAULT(ProdName) <##ProdName##\res\Resource.rc>
#ifdef _XTP_RESOURCE_LANGUAGE
#define LANGUAGE_LOCALIZED__(ProdName, LangName) <##ProdName##\res\Resource_##LangName##.rc>
#define LANGUAGE_LOCALIZED_(ProdName, LangName) LANGUAGE_LOCALIZED__(ProdName, LangName)
#define LANGUAGE_LOCALIZED(ProdName) LANGUAGE_LOCALIZED_(ProdName, _XTP_RESOURCE_LANGUAGE)
#else
#define LANGUAGE_LOCALIZED(ProdName) LANGUAGE_DEFAULT(ProdName)
#endif
当然也可以放在其他地方,只要在#ifdef _XTP_RESOURCE_LANGUAGE之前就好了。
四、在ToolkitPro.rc文件中找到
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
修改为
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
五、重新编译一下,就可以使用了。
注:我的编译后有一个函数使用的时候有点问题,不保证编译后,E文正确的中文也正确。本来想把汉化好的bin和lib分享给大家,无奈文件太大了,还好这个汉化的步骤不复杂,大家应该都可以成功。如果有问题,欢迎大家留言交流
UniCode 下 CString 转 char* 的方法的文章有很多,但是大部分都是在互相转载,看了那么多资料,仍然没有解决乱码的问题,后来从一个论坛的一条回复里面找到了正确的方法,特此拿出来与大家分享。
先总结一下网上找到的三种转换的方法:
方法一:使用函数setlocale
setlocale(LC_ALL,"chs");
需要包含头文件#include <locale.h>
此方法的思路是配置地域化信息。通常在需要输入输出中文的时候设置一下,就没问题了,setlocale详情 点我
方法二:使用函数:T2A、W2A
CString str = _T("D://校内项目//QQ.bmp");
//声明标识符
USES_CONVERSION;
//调用函数,T2A和W2A均支持ATL和MFC中的字符转换
char *
pFileName = T2A(str);
//char * pFileName =
W2A(str); //也可实现转换
注意:有时候可能还需要添加引用#include <afxpriv.h>
使用此方法要注意声明标识符,T2A、W2A详情 点我
方法三:使用API:WideCharToMultiByte进行转换
CString str = _T("D://校内项目//QQ.bmp");
//注意:以下n和len的值大小不同,n是按字符计算的,len是按字节计算的
int n =
str.GetLength(); // n = 14, len = 18
//获取宽字节字符的大小,大小是按字节计算的
int len
= WideCharToMultiByte(CP_ACP,0,str,str.GetLength(),NULL,0,NULL,NULL);
//为多字节字符数组申请空间,数组大小为按字节计算的宽字节字节大小
char *
pFileName = new char[len+1]; //以字节为单位
//宽字节编码转换成多字节编码
WideCharToMultiByte(CP_ACP,0,str,str.GetLength(),pFileName,len,NULL,NULL);
WideCharToMultiByte(CP_ACP,0,str,str.GetLength() + 1 ,pFileName,len + 1 ,NULL,NULL);
pFileName[len+1] = '/0'; //多字节字符以'/0'结束
这三种方法都是感觉比较靠谱的,也有很多人验证了可以成功,但是在我用的时候很悲催,三种方法都不行,经过仔细的考虑,发现第三种方法应该是万无一失,最保险的方法啊,后来经过仔细查找,原来是参数出了问题,黄色被我划掉的是网上流传的比较广泛的方法,WideCharToMultiByte(CP_ACP,0,str,str.GetLength() + 1 ,pFileName,len + 1 ,NULL,NULL);是我验证成功的写法,至于为什么是这样,留给大家自己思考。WideCharToMultiByte详情 点我
小弟才疏学浅,写的不对,敬请指正!
