三.ANSI/UNICODE字符串通用函数lstrcpy/lstrcmp/lstrcat/lstrlen

ntdll.dll中实现了许多CRT基本函数:

strlen/wcslenstrcpy/wcscpystrncpy/wcsncpystrcat/wcscatstrncat/wcsncatstrcmp/wcscmpstrncmp/wcsncmpstrchr/wcschrstrrchr/wcsrchrstrstr/wcsstrsprintf/swprintfstrtol/wcstolstrtoul/wcstoul

kernel32.dll(依赖ntdll.dll)中实现了:

lstrlen(lstrlenA/lstrlenW)lstrcpy(lstrcpyA/lstrcpyW)lstrcpyn(lstrcpynA/lstrcpynW)lstrcat(lstrcatA/lstrcatW)lstrcmp(lstrcmpA/lstrcmpW)lstrcmpi(lstrcmpiA/lstrcmpiW)

// \Microsoft Visual Studio 8\VC\PlatformSDK\Include\Winbase.h(已包含在windows.h中)

WINBASEAPI

LPSTR

WINAPI

lstrcpyA(

    __out LPSTR lpString1,

    __in  LPCSTR lpString2

    );

WINBASEAPI

LPWSTR

WINAPI

lstrcpyW(

    __out LPWSTR lpString1,

    __in  LPCWSTR lpString2

    );

#ifdef UNICODE

#define lstrcpy  lstrcpyW

#else

#define lstrcpy  lstrcpyA

#endif // !UNICODE

 

四.使用shlwapi头文件中定义的函数StrCat/StrCmp/StrCpy

Shlwapi.dll(依赖kernel32.dll)是UNCURL地址动态链接库文件,用于注册键值和色彩设置。因为操作系统字符串函数常常被大型应用程序比如操作系统的外壳进程Explorer.exe所使用。由于这些函数使用得很多,因此,在应用程序运行时,它们可能已经被装入RAM。这将有助于稍稍提高应用程序的运行性能。

注意:使用StrCatStrCmpStrCpy etc时要

#include 

#pragma comment(lib"Shlwapi.lib")

// …\Microsoft Visual Studio 8\VC\PlatformSDK\Include\Shlwapi.h

LWSTDAPI_(LPWSTR)   StrCatW(LPWSTR psz1LPCWSTR psz2);

LWSTDAPI_(int)      StrCmpW(LPCWSTR psz1LPCWSTR psz2);

LWSTDAPI_(LPWSTR)   StrCpyW(LPWSTR psz1LPCWSTR psz2);

#ifdef UNICODE

#define StrCat      StrCatW

#define StrCmp      StrCmpW

#define StrCpy      StrCpyW

#else

#define StrCat      lstrcatA

#define StrCmp      lstrcmpA

#define StrCpy      lstrcpyA

由上可以看出StrCpy调用的是lstrcpyStrCat调用的是lstrcatStrCmp调用的是lstrcmp

 

五.MFC动态字符串类CString

// …\Microsoft Visual Studio 8\VC\atlmfc\include\afx.h

一个CString对象由可变长度的一队字符组成。CString使用类似于Basic的语法提供函数和操作符。连接和比较操作符以及简化的内存管理使CString对象比普通字符串数组容易使用。

CString是基于TCHAR数据类型的对象。如果在你的程序中定义了符号_UNICODE,则TCHAR被定义为类型wchar_t,即16位字符类型;否则,TCHAR被定义为char,即8位字符类型。在UNICODE方式下,CString对象由16位字符组成。非UNICODE方式下,CString对象由8位字符组成。 而VS2005默认TCHARwchar而不是char.

当不使用_UNICODE时,CString是多字节字符集(MBCS,也被认为是双字节字符集,DBCS)。注意,对于MBCS字符串,CString仍然基于8位字符来计算,返回,以及处理字符串,并且你的应用程序必须自己解释MBCS的开始和结束字节。

CString 提供 operator LPCTSTR 来在 CString  LPCTSTR 之间进行转换。

有关CString的操作请参考MSDN MFC类库。参考源码文件AFX.HAFX.INLSTRCORE.CPPSTREX.CPP

 

六.更安全的C语言字符串处理函数 Strsafe.h

// …\Microsoft Visual Studio 8\VC\PlatformSDK\Include\strsafe.h

注意:使用StringCchCopy/StringCchPrintf时要#include .

STRSAFEAPI是为了解决现有的 C 语言运行时函数的代码太容易产生的内存溢出问题。当我们引用 strsafe 系列函数时,原有的 C 语言字符串处理函数都将被自动进行 #undef 处理。调试过程中的警告或出错信息将会告诉我们哪些函数哪些不安全,哪些已经被相应的 strsafe 系列函数取代了。 

1.不赞成使用不安全的函数,以避免产生编译错误

2.如果你不要安全处理,你可以在包含strsafe.h头文件之前,

#define STRSAFE_NO_DEPRECATE

#ifdef DEPRECATE_SUPPORTED

// First all the names that are a/w variants (or shouldn't be #defined by now anyway).

#pragma deprecated(strcpy)

#pragma deprecated(wcscpy)

#pragma deprecated(lstrcpy)

#pragma deprecated(StrCpy)

类似的Strcat/wcscat/lstrcat/StrCatsprintf/wsprintf

以下是D3D中预编译头文件dxstdafx.h

#pragma warningdisable : 4996 ) // 将报警置为无效

#include 

#pragma warningdefault : 4996 ) // 将报警置为默认

有关#pragma warning请参考《关于#pragma warning

以下是D3DVS2003移植到VS2005时遇到的安全警告:

warning C4996: 'wcscpy' was declared deprecated

see declaration of 'wcscpy'

Message: 'This function or variable may be unsafe.

Consider using wcscpy_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.'

warning C4995: 'lstrcpy': name was marked as #pragma deprecated

warning C4995: 'wsprintf': name was marked as #pragma deprecated

推荐使用新的安全可靠的TRSAFEAPI

STRSAFEAPI

StringCchCopyA(

__out_ecount(cchDestSTRSAFE_LPSTR pszDest,

__in size_t cchDest,

__in STRSAFE_LPCSTR pszSrc);

STRSAFEAPI

StringCchCopyW(

              __out_ecount(cchDestSTRSAFE_LPWSTR pszDest,

              __in size_t cchDest,

              __in STRSAFE_LPCWSTR pszSrc);

#ifdef UNICODE

#define StringCchCopy  StringCchCopyW (WWide Unicode)

#else

#define StringCchCopy  StringCchCopyA (AANSI)

#endif // !UNICODE

#undef strcpy

#define strcpy      strcpy_instead_use_StringCbCopyA_or_StringCchCopyA;

#undef wcscpy

#define wcscpy      wcscpy_instead_use_StringCbCopyW_or_StringCchCopyW;

#undef wsprintf

#define wsprintf    wsprintf_instead_use_StringCbPrintf_or_StringCchPrintf;

// Then all the windows.h names - we need to undef and redef based on UNICODE setting

#undef lstrcpy // 取消已定义的宏

#pragma deprecated(lstrcpy// 安全警告

#ifdef UNICODE // 使用UNICODE编程

#define lstrcpy    lstrcpyW // 重定义

#else

#define lstrcpy    lstrcpyA // 重定义

#endif

类似的有对lstrcat/wsprintf/wvsprintf#undef#pragma deprecated#define

推荐使用新的安全可靠的TRSAFEAPI

#undef lstrcpy

#define lstrcpy     lstrcpy_instead_use_StringCbCopy_or_StringCchCopy;

// Then the shlwapi names - they key off UNICODE also.

#undef  StrCpy

#pragma deprecated(StrCpy)

#ifdef UNICODE

#define StrCpy  StrCpyW

#else

#define StrCpy  lstrcpyA

#endif

类似的有#undef StrCpyA /StrCpy /StrCatA /StrCat /StrNCat /StrCatN以及对StrCpy/StrCat/StrNCat#undef#pragma deprecated#define

推荐使用新的安全可靠的TRSAFEAPI

#undef StrCpy

#define StrCpy      StrCpy_instead_use_StringCbCopy_or_StringCchCopy;

// Then all the CRT names - we need to undef/redef based on _UNICODE value.

 

七.VC编译UNICODE版本

VC6.0支持Unicode,但在缺省安装情况下,没有把相关的部件安装上去,所以第一步要安装相关的组件。从安装向导中选择自定义,在选择要安装的组件清单时,把vc里面带unicode的子项全部选中安装即可。

如果采用默认安装,后期需要编译发布Unicode版本,在“Project SettingàC/C++CategoryPreprocessoràPreprocessor definitions”处使用_UNICODE UNICODE替换掉_MBCS

程序运行可能会提示找不到MFC42U.DLLMFC42UD.DLLMFCO42UD.DLLUUnicodeDDebugOOle)等,这是由于VC++ 安装的时候没有选择UNICODE支持的缘故,导致没有安装debug版本的MFC42*.DLL。如果只是运行需要的话,可以从VC安装盘(Visual Studio 6安装包目录\VC98\REDIST\MFC42U.DLLVisual Studio 6安装包目录\VC98\DEBUG\MFC*.DLL)或其它机器copy过来,如果编译使用,建议还是重装来得实在。