📄 article3.htm
字号:
</FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>WCHAR</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>The Win32 version of wchar_t.
</FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>OLECHAR</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>The OLE version of wchar_t.
</FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>_TCHAR</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>A generic character that maps to char or wchar_t.
</FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>LPSTR, LPCSTR</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>A Win32 character pointer. The version with C is const. </FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>LPWSTR, LPCWSTR</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>A Win32 wide character pointer.
</FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>LPOLESTR, LPCOLESTR</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>An OLE wide character pointer. </FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>LPTSTR, LPCTSTR</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>A Win32 generic character pointer.
</FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>_T(<i>str</i>), _TEXT(<i>str</i>)</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>Identical macros to create generic constant strings.
</FONT></TD></TR>
<TR VALIGN=TOP>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>OLESTR(<i>str</i>)</FONT></TD>
<TD><font face="Verdana, Arial, Helvetica, Sans-Serif" SIZE=2>OLE macro to create generic constant strings. </FONT></TD></TR>
</TABLE>
<p>Do you notice a little redundancy here? A little inconsistency? The sample code uses the Win32 versions of these types, except when there isn't any Win32 version or the moon is full.<P>In normal C++ programming, you should use the generic versions of functions and types as much as possible so that your strings will work in either Unicode or ANSI builds. In this series, the <b>String</b> class hides a lot of the detail of making things generic. Generally it provides overloaded ANSI and Unicode versions of functions rather than using generic types. When you have a choice, you should use Unicode strings rather than ANSI or generic strings. You'll see how and why this nontypical coding style works later. <P><blockquote>Note: Versions of Visual C++ before 4.0 had a DLL called OLE2ANSI that automatically translated OLE Unicode strings to ANSI strings behind the scenes. This optimistic DLL tried to do the impossible. It was indeed pleasant to have the bothersome details taken care of, but performance-wise, users were living in a fool's paradise. OLE2ANSI is history now, although conditional symbols for it still exist in the OLE include files. The OLECHAR type, rather than the WCHAR type, was used in OLE prototypes so that it could be transformed into the CHAR type by this DLL. Do not define the symbol OLE2ANSI in the hopes that OLE strings will magically transform themselves into ANSI strings. There is no Santa Claus. </blockquote><P><h2>What Is a BSTR?</h2><P>The BSTR type is actually a <b>typedef</b>, which in typical Windows include file fashion, is made up of more <b>typedef</b>s and <b>defines</b>. You can follow the twisted path yourself, but here's what it boils down to: <P><PRE><FONT FACE="COURIER" SIZE="2">typedef wchar_t * BSTR;
</FONT></PRE><P>Hmmm. A BSTR is actually a pointer to Unicode characters. Does that look familiar? In case you don't recognize this, let me point out a couple of similar <b>typedef</b>s: <P><PRE><FONT FACE="COURIER" SIZE="2">typedef wchar_t * LPWSTR;
typedef char * LPSTR;
</FONT></PRE><P>So if a BSTR is just a pointer to characters, how is it different from the null-terminated strings that C++ programmers know so well? Internally, the difference is that there's something extra at the start and end of the string. The string length is maintained in a long variable just before the start address being pointed to, and the string always has an extra null character after the last character of the string. This null isn't part of the string, and you may have additional nulls embedded in the string. <P>That's the technical difference. The philosophical difference is that the contents of BSTRs are sacred. You're not allowed to modify the characters except according to very strict rules that we'll get to in a minute. OLE provides functions for allocating, reallocating, and destroying BSTRs. If you own an allocated BSTR, you may modify its contents as long as you don't change its size. Because every BSTR is, among other things, a pointer to a null-terminated string, you may pass one to any string function that expects a read-only (const) C string. The rules are much tighter for passing BSTRs to functions that modify string buffers. Usually, you can only use functions that take a string buffer argument and a maximum length argument. <P>All the rules work on the honor system. A BSTR is a BSTR by convention. Real types can be designed to permit only legal operations. Later we'll define a C++ type called String that does its best to enforce the rules. The point is that BSTR servers are honor-bound to follow the rules so that BSTR clients can use strings without even knowing that there are rules.
<P><h3>The BSTR System Functions</h3><P>My descriptions of the OLE BSTR functions are different from and, in my opinion, more complete than the descriptions in OLE documentation. I had to experiment to determine some behavior that was scantily documented, and I checked the include files to get the real definitions, so I am confident that my descriptions are valid and will work for you.<P>For consistency with the rest of the article, the syntax used for code in this section has been normalized to use Win32 types such as LPWSTR and LPCWSTR. The actual prototypes in OLEAUTO.H use const OLECHAR FAR * (ignoring the equivalent LPCOLESTR types). The original reasons for using OLECHAR pointers rather than LPCWSTRs don't matter for this article.
<P>You need to read this section only if you want to fully understand how the <b>String</b> class (presented later) works. But you don't really need to understand BSTRs in order to use the <b>String</b> class.<P><h4>BSTR SysAllocString(LPCWSTR wsz);</H4><P>Given a null-terminated wide character string, allocates a new BSTR of the same length and copies the string to the BSTR. This function works for empty and null strings. If you pass in a null string, you get back a null string. You also get back a null string if there isn't enough memory to allocate the given string. <P><b>Example:</b><P><PRE><FONT FACE="COURIER" SIZE="2">// Create BSTR containing "Text"
bs = SysAllocString(L"Text")
</FONT></PRE><P><h4>BSTR SysAllocStringLen(LPCWSTR wsz, unsigned len);</H4><P>Given a null-terminated wide-character string and a maximum length, allocates a new BSTR of the given length and copies up to that length of characters from the string to the BSTR. If the length of the copied string is less than the given maximum length, a null character is written after the last copied character. The rest of the requested length is allocated, but not initialized (except that there will always be a null character at the end of the BSTR). Thus the string will be doubly null-terminated--once at the end of the copied characters and once at the end of the allocated space. If NULL is passed as the string, the whole length is allocated, but not initialized (except for the terminating null character). Don't count on allocated but uninitialized strings to contain null characters or anything else in particular. It's best to fill uninitialized strings as soon after allocation as possible. <P><b>Example:</b><P><PRE><FONT FACE="COURIER" SIZE="2">// Create BSTR containing "Te"
bs = SysAllocStringLen(L"Text", 2)
// Create BSTR containing "Text" followed by \0 and a junk character
bs = SysAllocStringLen(L"Text", 6)
</FONT></PRE><P><h4>BSTR SysAllocStringByteLen(LPSTR sz, unsigned len);</H4><P>Given a null-terminated ANSI string, allocates a new BSTR of the given length and copies up to that length of bytes from the string to the BSTR. The result is a BSTR with two ANSI characters crammed into each wide character. There is very little you could do with such a string, and therefore not much reason to use this function. It's there for string conversion operations such as Visual Basic's <b>StrConv</b> function. What you really want is a function that creates a BSTR from an ANSI string, but this isn't it. The function works like <b>SysAllocStringLen</b> if you pass a null pointer or a length greater than the length of the input string.<P><h4>BOOL SysReAllocString(BSTR * pbs, LPWSTR wsz);</H4><P>Allocates a new BSTR of the same length as the given wide-character string, copies the string to the BSTR, frees the BSTR pointed to by the first pointer, and resets the pointer to the new BSTR. Notice that the first parameter is a pointer to a BSTR, not a BSTR. Normally, you'll pass a BSTR pointer with the address-of operator. <P><b>Example:</b><P><PRE><FONT FACE="COURIER" SIZE="2">// Reallocate BSTR bs as "NewText"
f = SysReAllocString(&bs, "NewText");
</FONT></PRE><P><h4>BOOL SysReAllocStringLen(BSTR * pbs, LPWSTR wsz, unsigned len);</H4><P>Allocates a new BSTR of the given length, and copies as many characters as fit of the given wide-character string to the new BSTR. It then frees the BSTR pointed to by the first pointer and resets the pointer to the new BSTR. Often the new pointer will be the same as the old pointer, but you shouldn't count on this. You can give the same BSTR for both arguments if you want to truncate an existing BSTR. For example, you might allocate a BSTR buffer, call an API function to fill the buffer, and then reallocate the string to its actual length. <P><b>Example:</b><P><PRE><FONT FACE="COURIER" SIZE="2">// Create uninitialized buffer of length MAX_BUF.
BSTR bsInput = SysAllocStringLen(NULL, MAX_BUF);
// Call API function to fill the buffer and return actual length.
cch = GetTempPathW(MAX_BUF, bsInput);
// Truncate string to actual length.
BOOL f = SysReAllocStringLen(&bsInput, bsInput, cch);
</FONT></PRE><P><h4>unsigned SysStringLen(BSTR bs);</H4><P>Returns the length of the BSTR in characters. This length does not include the terminating null. This function will return zero as the length of either a null BSTR or an empty BSTR. <P><b>Example:</b><P><PRE><FONT FACE="COURIER" SIZE="2">// Get character length of string.
cch = SysStringLen(bs);
</FONT></PRE><P><h4>unsigned SysStringByteLen(BSTR bs);</H4><P>Returns the length of the BSTR in bytes, not including the terminating null. This information is rarely of any value. Note that if you look at the length prefix of a BSTR in a debugger, you'll see the byte length (as returned by this function) rather than the character length. <P><h4>void SysFreeString(BSTR bs);</H4><P>Frees the memory assigned to the given BSTR. The contents of the string may be completely freed by the operating system, or they may just sit there unchanged. Either way, they no longer belong to you and you had better not read or write to them. Don't confuse a deallocated BSTR with a null BSTR. The null BSTR is valid; the deallocated BSTR is not. <P><b>Example:</b><P><PRE><FONT FACE="COURIER" SIZE="2">// Deallocate a string.
SysFreeString(bs);
</FONT></PRE><P><h4>BSTR SysAllocStringA(LPCSTR sz);</H4><P>The same as <b>SysAllocString</b>, except that it takes an ANSI string argument. OLE doesn't provide this function; it's declared in BString.H and defined in BString.Cpp. Normally, you should only use this function to create Unicode BSTRs from ANSI character string variables or function return values. It works for ANSI string literals, but it's wasted effort because you could just declare Unicode literals and save yourself some run-time processing. <P><b>Example: </b><P><PRE><FONT FACE="COURIER" SIZE="2">// Create BSTR containing "Text".
bs = SysAllocStringA(sz)
</FONT></PRE><P><h4>BSTR SysAllocStringLenA(LPCSTR sz, unsigned len);</H4><P>The same as <b>SysAllocStringLen</b>, except that it takes an ANSI string argument. This is my enhancement function, declared in BString.H. <P><b>Example:</b><P><PRE><FONT FACE="COURIER" SIZE="2">// Create BSTR containing six characters, some or all of them from sz.
bs = SysAllocStringLenA(sz, 6)
</FONT></PRE><P><h3>The Eight Rules of BSTR</h3><P>Knowing what the BSTR functions do doesn't mean you know how to use them. Just as the BSTR type is more than its <b>typedef</b> implies, the BSTR functions require more knowledge than documentation states. Those who obey the rules live in peace and happiness. Those who violate them live in fear--plagued by the ghosts of bugs past and future. <P>The trouble is, these rules are passed on in the oral tradition; they are not carved in stone. You're just supposed to know. The following list is an educated attempt--based on scraps of ancient manuscripts, and revised through trial and error--to codify the oral tradition. Remember, it is just an attempt.<P><h4>Rule 1: Allocate, destroy, and measure BSTRs only through the OLE API (the Sys functions).</H4><P>Those who use their supposed knowledge of BSTR internals are doomed to an unknowable but horrible fate in future versions. (You have to follow the rules if you don't want bugs.)<P><h4>Rule 2: You may have your way with all the characters of strings you own.</H4><P>The last character you own is the last character reported by <b>SysStringLen</b>, not the last non-null character. You may fool functions that believe in null-terminated strings by inserting null characters in BSTRs, but don't fool yourself. <P><h4>Rule 3: You may change the pointers to strings you own, but only by following the rules.</H4><P>In other words, you can change those pointers with <b>SysReAllocString</b> or <b>SysReAllocStringLen</b>. The trick with this rule (and rule 2) is determining whether you own the strings. <P><h4>Rule 4: You do not own any BSTR passed to you by value.</H4><P>The only thing you can do with such a string is copy it or pass it on to other functions that won't modify it. The caller owns the string and will dispose of it according to its whims. A BSTR passed by value looks like this in C++:<P><PRE><FONT FACE="COURIER" SIZE="2">void DLLAPI TakeThisStringAndCopyIt(BCSTR bsIn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -