zoukankan      html  css  js  c++  java
  • 理解BSTR数据类型 神奇的BSTR

    理解BSTR数据类型 神奇的BSTR - 深蓝的日志 - 网易博客 http://blog.163.com/pugood@126/blog/static/1344175932009111111526409/

    多数支持COM的语言都没法处理单以NULL结尾的字符数组(不管是否是UNICODE)。

    Visual Basic, Java, VBScript, 还有 Jscript都希望字符串是固定字节长度的。

    BSTR数据类型是一个UNICODE,固定字节长度,且以NULL结尾的字符串,所有的COM兼容语言都 可以使用。

    虽然所有的COM兼容的语言都能使用BSTR,但它们都以自己的方式操作。VB程序员用下面的代码创建BSTR:

    ' VB developer made a BSTR.
    '
    Dim name as String
    name = "Fred Flintstone"

    作为C++程序员,我们使用一组COM包创建,操作BSTR数据。每个BSTR方法名都有"Sys-"前缀,用以表示是操作BSTR的(system string)。

    比较有趣的是BSTR是个OLECHAR*的typedef,所以它是一个OLECHAR字符数组。

    // Behold the BSTR (<wtypes.h>).
    typedef OLECHAR*          BSTR;

    操作BSTR的方法才是真正有区别的地方。下面我们就看一下常用的BSTR方法,了解什么时候去使用它。


    在C++中创建BSTR

    当你要在C++中创建BSTR的时候,你需要使用SysAllocString()。这个方法会计算字符串的长度并设置足够的缓存。例如,我们传入一个UNICODE的字符串,用bstrName变量来保持返回值:

    // SysAllocString() creates a BSTR.
    BSTR bstrName;
    bstrName = SysAllocString(L"Fred Flintstone");

    当然,多数情况下你不想使用硬代码的字符串来初始化BSTR,而使用变量。应此,你可以使用OLECHAR*变量来创建BSTR(使用OLESTR宏来确保使用正确的类型):

    // Create a BSTR using an array of OLECHAR types (could be char or wchar_t).
    OLECHAR* pOLEStr;     
    pOLEStr = OLESTR("Fred Flinstone");
    BSTR bstrName;
    bstrName = SysAllocString(pOLEStr);

    操作BSTR

    一旦你创建了一个BSTR,你很有可能在程序中会重设它的值。使用SysReAllocString()来修改一个现有的BSTR,它会释放之前的空间,重新计算字符串的长度和设置缓存:

    // Change existing bstrName to 'Mr. Slate'
    SysReAllocString(&bstrName, L"Mr. Slate");

    SysStringLen()方法给你计算现存BSTR缓存的长度:

    // Mr. Slate == 9
    int length = SysStringLen(bstrName);

    重要的是,任何一个使用SysAllocString()创建BSTR必须使用SysFreeString()来清除。任何一个你从接口方法获得的BSTR也需要使用SysFreeString()来清除。

    // All done with the string.
    SysFreeString(bstrName);

    注意:忘记使用SysFreeString()来清除BSTR会导致内存泄漏。这个的重要性就和在C++中用NEW来获得内存而忘记用DELETE删除是一样的。

    额外的BSTR方法

    SysAllocString(), SysStringLen(), 和 SysFreeString()方法是学习操作BSTR的好开始,BSTR的API还定义了一些其他的方法。这里列举 了<oleauto.h>中定义的所有的方法,在线帮助里有更完善的注解:

    SysAllocString()
    创建一个新的BSTR 。

    SysReAllocString()
    重新设置一个已存在的BSTR 。

    SysStringLen()
    返回BSTR 的长度。

    SysFreeString()
    销毁已存在的BSTR 。

    SysReAllocStringLen()
    Used to create a BSTR based on some length of characters.

    SysStringByteLen()
    返回BSTR的字节长度。(Win32)

    SysAllocStringByteLen()
    使用二进制数据来创建BSTR。你只能在不存在ANSI 到Unicode 或是Unicode 到ANSI转换的情况下使用。(Win32)


    Unicode 到 ANSI转换

    即使我们都能接纳BSTR(最大化的做到语言独立性),我们还有一个未解决的问题。WIN32 API的字符串参数通常都是ANSI类型。如:我们广泛使用的MessageBox()看起来是这样:

    // This is the MessageBox() method we think we know...
    MessageBox (HWND hWnd , LPCSTR lpText, LPCSTR lpCaption, UINT uType);

    根据上面的方法原型,它看起来像是我们需要提供2个字符数组常量(LPCSTR =指向常量字符数组的长指针)。然而,现实总是很奇怪,事实上WIN32 API中根本就没有MessageBox()方法。实际上这个方法(所有包含字符串参数的WIN32方法)定义成2个可能的形式:

    // Every Win32 function which takes text strings has an ANSI (A) or Unicode(W)
    // variation.
    #ifdef UNICODE
         #define MessageBox MessageBoxW
    #else
         #define MessageBox MessageBoxA
    #endif // !UNICODE

    在WIN NT下,当你选择使用UNICODE编译你的当前项目时,就会定义UNICODE预处理标志(在Project | Settings菜单中选择)。在这种情况下,API中所有的方法就会自动转变成宽字符版本。例如MessageBox()会转换为下面的形式:

    // Under Unicode builds, all strings come through as an array of constant wchar_t.
    MessageBoxW( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);

    在非UNICODE结构下,MessageBox()转变成ANSI字符版本:

    // ANSI builds use const char arrays.
    MessageBoxA (HWND hWnd , LPCSTR lpText, LPCSTR lpCaption, UINT uType);

    我们遇到了进退两难的情况,如果我们选择UNICODE结构,我们的项目就只能在WIN NT下正确运行。如果我们选择非UNICODE结构,程序就可以运行在所有的平台上,虽然在UNICODE平台上(比如WIN NT)会执行ANSI到UNICODE的转换(意味着会降低效率)。

    用于转换的方法

    WIN32定义了2个很强大的方法,让你将ANSI转换成UNICODE,或是将UNICODE转换成ANSI。这2个方法给你最大的灵活性。但是鉴于他们复杂的参数,稍显难用:

    ? MultiByteToWideChar(): Converts an ANSI string to a Unicode equivalent.
    ? WideCharToMultiByte(): Converts a Unicode string to an ANSI equivalent.

    还有一个选择,C的运行期库提供了较为简单,方便,且跨平台的转换方法。如果你想将UNICODE(例如BSTR)字符串转换为ANSI字符串,可以调用wcstombs()方法(Wide Character String to Multibyte String):

    // wcstombs( char *ANSIString, wchar_t *UNICODEString, size_t count );
    char buff[MAX_LENGTH];
    BSTR bstr = SysAllocString(L"How did strings get so ugly?");
    wcstombs(buff, bstr, MAX_LENGTH);          // P3 = size of target buffer.
    cout << buff << endl;                      // Pump to console.
    SysFreeString(bstr);

    如果你想将ANSI字符串转换为UNICODE,调用mbstowcs()方法(Multi Byte String to Wide Character String):

    // Transform an existing char* (ANSI) into a wchar_t* (Unicode)
    mbstowcs( wchar_t *UNICODEString , char *ANSIString, size_t count );

    当我们从COM转移到ATL后,我们将有一整套用于转换的宏,简化字符的转换操作,忘掉之前的4个方法。同时,ATL中的CComBSTR类将我们从复杂的字符串方法中解救出来。但是现在,我们还有很长的一段路要走,也仍然要使用那些转换的方法。

  • 相关阅读:
    GitHub上受欢迎的Android UI Library
    推荐的优秀博客--多关注,多看看
    Android SDK在线更新镜像服务器大全
    SqlServer查看各个表所占空间大小的sql
    演化理解 Android 异步加载图片
    tsp、rtmp测试地址
    eclipse离线安装Properties Editor插件查看配置文件中Unicode内容
    亲测成功关闭谷歌浏览器自动更新方法分享 取消chrome自动更新
    SQL Server 中用While循环替代游标(Cursor的解决方案
    【转】service和serviceImpl的选择
  • 原文地址:https://www.cnblogs.com/wxl845235800/p/7413777.html
Copyright © 2011-2022 走看看