ASCII,Unicode, BSTR,LPSTR和LPWSTR轉換...

一、BSTR、LPSTR和LPWSTR
  在Visual C++.NET的所有編程方式中,我們常常要用到這樣的一些基本字符串類型,如BSTR、LPSTR和LPWSTR等。之所以出現類似上述的這些數據類型,是因爲不同編程語言之間的數據交換以及對ANSI、Unicode和多字節字符集(MBCS)的支持。
  那麼什麼是BSTR、LPSTR以及LPWSTR呢?
  BSTR(Basic STRing,Basic字符串)是一個OLECHAR*類型的Unicode字符串。它被描述成一個與自動化相兼容的類型。由於操作系統提供相應的API函數(如SysAllocString)來管理它以及一些默認的調度代碼,因此BSTR實際上就是一個COM字符串,但它卻在自動化技術以外的多種場合下得到廣泛使用。圖1描述了BSTR的結構,其中DWORD值是字符串中實際所佔用的字節數,且它的值是字符串中Unicode字符的兩倍。
  LPSTR和LPWSTR是Win32和VC++所使用的一種字符串數據類型。LPSTR被定義成是一個指向以NULL(‘/0’)結尾的8位ANSI字符數組指針,而LPWSTR是一個指向以NULL結尾的16位雙字節字符數組指針。在VC++中,還有類似的字符串類型,如LPTSTR、LPCTSTR等,它們的含義如圖2所示。
  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一個指向一般字符串常量的長指針類型”,與C/C++的const char*相映射,而LPTSTR映射爲 char*。
  一般地,還有下列類型定義:
#ifdef UNICODE
 typedef LPWSTR LPTSTR;
 typedef LPCWSTR LPCTSTR;
#else
 typedef LPSTR LPTSTR;
 typedef LPCSTR LPCTSTR;
#endif
二、CString、CStringA 和 CStringW
  Visual C++.NET中將CStringT作爲ATL和MFC的共享的“一般”字符串類,它有CString、CStringA和CStringW三種形式,分別操作不同字符類型的字符串。這些字符類型是TCHAR、char和wchar_t。TCHAR在Unicode平臺中等同於WCHAR(16位Unicode字符),在ANSI中等價於char。wchar_t通常定義爲unsigned short。由於CString在MFC應用程序中經常用到,這裏不再重複。
三、VARIANT、COleVariant 和_variant_t
  在OLE、ActiveX和COM中,VARIANT數據類型提供了一種非常有效的機制,由於它既包含了數據本身,也包含了數據的類型,因而它可以實現各種不同的自動化數據的傳輸。下面讓我們來看看OAIDL.H文件中VARIANT定義的一個簡化版:
struct tagVARIANT {
 VARTYPE vt;
 union {
  short iVal; // VT_I2.
  long lVal; // VT_I4.
  float fltVal; // VT_R4.
  double dblVal; // VT_R8.
  DATE date; // VT_DATE.
  BSTR bstrVal; // VT_BSTR.
  …
  short * piVal; // VT_BYREF|VT_I2.
  long * plVal; // VT_BYREF|VT_I4.
  float * pfltVal; // VT_BYREF|VT_R4.
  double * pdblVal; // VT_BYREF|VT_R8.
  DATE * pdate; // VT_BYREF|VT_DATE.
  BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
 };
};
  顯然,VARIANT類型是一個C結構,它包含了一個類型成員vt、一些保留字節以及一個大的union類型。例如,如果vt爲VT_I2,那麼我們可以從iVal中讀出VARIANT的值。同樣,當給一個VARIANT變量賦值時,也要先指明其類型。例如:
VARIANT va;
:: VariantInit(&va); // 初始化
int a = 2002;
va.vt = VT_I4; // 指明long數據類型
va.lVal = a; // 賦值
  爲了方便處理VARIANT類型的變量,Windows還提供了這樣一些非常有用的函數:
  VariantInit —— 將變量初始化爲VT_EMPTY;
  VariantClear —— 消除並初始化VARIANT;
  VariantChangeType —— 改變VARIANT的類型;
  VariantCopy —— 釋放與目標VARIANT相連的內存並複製源VARIANT。
  COleVariant類是對VARIANT結構的封裝。它的構造函數具有極爲強大大的功能,當對象構造時首先調用VariantInit進行初始化,然後根據參數中的標準類型調用相應的構造函數,並使用VariantCopy進行轉換賦值操作,當VARIANT對象不在有效範圍時,它的析構函數就會被自動調用,由於析構函數調用了VariantClear,因而相應的內存就會被自動清除。除此之外,COleVariant的賦值操作符在與VARIANT類型轉換中爲我們提供極大的方便。例如下面的代碼:
COleVariant v1("This is a test"); // 直接構造
COleVariant v2 = "This is a test";
// 結果是VT_BSTR類型,值爲"This is a test"
COleVariant v3((long)2002);
COleVariant v4 = (long)2002;
// 結果是VT_I4類型,值爲2002
  _variant_t是一個用於COM的VARIANT類,它的功能與COleVariant相似。不過在Visual C++.NET的MFC應用程序中使用時需要在代碼文件前面添加下列兩句:
  #include "comutil.h"
  #pragma comment( lib, "comsupp.lib" )
四、CComBSTR和_bstr_t
  CComBSTR是對BSTR數據類型封裝的一個ATL類,它的操作比較方便。例如:
CComBSTR bstr1;
bstr1 = "Bye"; // 直接賦值
OLECHAR* str = OLESTR("ta ta"); // 長度爲5的寬字符
CComBSTR bstr2(wcslen(str)); // 定義長度爲5
wcscpy(bstr2.m_str, str); // 將寬字符串複製到BSTR中
CComBSTR bstr3(5, OLESTR("Hello World"));
CComBSTR bstr4(5, "Hello World");
CComBSTR bstr5(OLESTR("Hey there"));
CComBSTR bstr6("Hey there");
CComBSTR bstr7(bstr6);
// 構造時複製,內容爲"Hey there"
  _bstr_t是是C++對BSTR的封裝,它的構造和析構函數分別調用SysAllocString和SysFreeString函數,其他操作是借用BSTR API函數。與_variant_t相似,使用時也要添加comutil.h和comsupp.lib。
五、BSTR、char*和CString轉換
  (1) char*轉換成CString
  若將char*轉換成CString,除了直接賦值外,還可使用CString::Format進行。例如:
char chArray[] = "This is a test";
char * p = "This is a test";
  或
LPSTR p = "This is a test";
  或在已定義Unicode應的用程序中
TCHAR * p = _T("This is a test");
  或
LPTSTR p = _T("This is a test");
CString theString = chArray;
theString.Format(_T("%s"), chArray);
theString = p;
  (2) CString轉換成char*
  若將CString類轉換成char*(LPSTR)類型,常常使用下列三種方法:
  方法一,使用強制轉換。例如:
CString theString( "This is a test" );
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;
  方法二,使用strcpy。例如:
CString theString( "This is a test" );
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
_tcscpy(lpsz, theString);
  需要說明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二個參數是 const wchar_t* (Unicode)或const char* (ANSI),系統編譯器將會自動對其進行轉換。
  方法三,使用CString::GetBuffer。例如:
CString s(_T("This is a test "));
LPTSTR p = s.GetBuffer();
// 在這裏添加使用p的代碼
if(p != NULL) *p = _T('/0');
s.ReleaseBuffer();
// 使用完後及時釋放,以便能使用其它的CString成員函數
  (3) BSTR轉換成char*
  方法一,使用ConvertBSTRToString。例如:
#include
#pragma comment(lib, "comsupp.lib")
int _tmain(int argc, _TCHAR* argv[]){
BSTR bstrText = ::SysAllocString(L"Test");
char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
SysFreeString(bstrText); // 用完釋放
delete[] lpszText2;
return 0;
}
  方法二,使用_bstr_t的賦值運算符重載。例如:
_bstr_t b = bstrText;
char* lpszText2 = b;
  (4) char*轉換成BSTR
  方法一,使用SysAllocString等API函數。例如:
BSTR bstrText = ::SysAllocString(L"Test");
BSTR bstrText = ::SysAllocStringLen(L"Test",4);
BSTR bstrText = ::SysAllocStringByteLen("Test",4);
  方法二,使用COleVariant或_variant_t。例如:
//COleVariant strVar("This is a test");
_variant_t strVar("This is a test");
BSTR bstrText = strVar.bstrVal;
  方法三,使用_bstr_t,這是一種最簡單的方法。例如:
BSTR bstrText = _bstr_t("This is a test");
  方法四,使用CComBSTR。例如:
BSTR bstrText = CComBSTR("This is a test");
  或
CComBSTR bstr("This is a test");
BSTR bstrText = bstr.m_str;
  方法五,使用ConvertStringToBSTR。例如:
char* lpszText = "Test";
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);
  (5) CString轉換成BSTR
  通常是通過使用CStringT::AllocSysString來實現。例如:
CString str("This is a test");
BSTR bstrText = str.AllocSysString();

SysFreeString(bstrText); // 用完釋放
  (6) BSTR轉換成CString
  一般可按下列方法進行:
BSTR bstrText = ::SysAllocString(L"Test");
CStringA str;
str.Empty();
str = bstrText;
  或
CStringA str(bstrText);
  (7) ANSI、Unicode和寬字符之間的轉換
  方法一,使用MultiByteToWideChar將ANSI字符轉換成Unicode字符,使用WideCharToMultiByte將Unicode字符轉換成ANSI字符。
  方法二,使用“_T”將ANSI轉換成“一般”類型字符串,使用“L”將ANSI轉換成Unicode,而在託管C++環境中還可使用S將ANSI字符串轉換成String*對象。例如:
TCHAR tstr[] = _T("this is a test");
wchar_t wszStr[] = L"This is a test";
String* str = S”This is a test”;
  方法三,使用ATL 7.0的轉換宏和類。ATL7.0在原有3.0基礎上完善和增加了許多字符串轉換宏以及提供相應的類,它具有如圖3所示的統一形式:
  其中,第一個C表示“類”,以便於ATL 3.0宏相區別,第二個C表示常量,2表示“to”,EX表示要開闢一定大小的緩衝。SourceType和DestinationType可以是A、T、W和OLE,其含義分別是ANSI、Unicode、“一般”類型和OLE字符串。例如,CA2CT就是將ANSI轉換成一般類型的字符串常量。下面是一些示例代碼:
LPTSTR tstr= CA2TEX<16>("this is a test");
LPCTSTR tcstr= CA2CT("this is a test");
wchar_t wszStr[] = L"This is a test";
char* chstr = CW2A(wszStr);
ASCII
鍵盤
ASCII
鍵盤
ASCII
鍵盤
ASCII
鍵盤

27

ESC

32

SPACE

33

!

34

"

35

#

36

$

37

%

38

&

39

'

40

(

41

)

42

*

43

+

44

'

45

-

46

.

47

/

48

0

49

1

50

2

51

3

52

4

53

5

54

6

55

7

56

8

57

9

58

:

59

;

60

<

61

=

62

>

63

?

64

@

65

A

66

B

67

C

68

D

69

E

70

F

71

G

72

H

73

I

74

J

75

K

76

L

77

M

78

N

79

O

80

P

81

Q

82

R

83

S

84

T

85

U

86

V

87

W

88

X

89

Y

90

Z

91

[

92

/

93

]

94

^

95

_

96

`

97

a

98

b

99

c

100

d

101

e

102

f

103

g

104

h

105

i

106

j

107

k

108

l

109

m

110

n

111

o

112

p

113

q

114

r

115

s

116

t

117

u

118

v

119

w

120

x

121

y

122

z

123

{

124

|

125

}

126

~

Test 1
A character pointer, string, and BSTR that work with ASCII and Unicode compilation.


LPCTSTR r;r = TEXT("hello");CString s;s = r;BSTR b;b = s.AllocSysString();SysFreeString(b);

When compiled for ASCII
r is narrow, type const char *
s is narrow, type ATL::CStringT<char,ATL::StrTraitATL<char,ATL::ChTraitsCRT<char> > >
b is wide, type unsigned short *

When compiled for Unicode
r is wide, type const unsigned short *
s is wide, type ATL::CStringT<unsigned short,ATL::StrTraitATL<unsigned short,ATL::ChTraitsCRT<unsigned short> > >
b is wide, type unsigned short *

Test 2
Compiled in Unicode, the CString type turns ASCII string literals into wide character strings.


CString s1;s1 = "hello1";CString s2 = "hello2";CString s3("hello3");

When compiled for ASCII, all 3 strings are made up of narrow characters. When compiled for Unicode, all 3 strings are made up of wide characters, even though the string literals are not escaped with L or TEXT().

notes

goal:
a sample mfc app
that i can compile ascii or unicode
that has a string type
that has functions like has, find, split, before
that has a class that can produce a BSTR
the class can produce ASCII text to write to a file even when compiled for unicode

string literals
"hello"
L"hello"
TEXT("hello")

string types
CString
LPCTSTR
LPTSTR
TCHAR
const WCHAR *
BSTR

compile
#ifdef _UNICODE
#else
#endif

functions
MultiByteToWideChar
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章