??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品无码专区久久同性男,精品久久久久久中文字幕人妻最新,国产精品久久久久久搜索http://www.shnenglu.com/gtwdaizi/category/5210.htmlzh-cnThu, 30 Oct 2008 03:56:52 GMTThu, 30 Oct 2008 03:56:52 GMT60[Windows Moble/VC++]GetCurrentTime()/GetLocalTime()/GetTickCount()http://www.shnenglu.com/gtwdaizi/articles/49177.html郭天?/dc:creator>郭天?/author>Thu, 08 May 2008 01:34:00 GMThttp://www.shnenglu.com/gtwdaizi/articles/49177.htmlhttp://www.shnenglu.com/gtwdaizi/comments/49177.htmlhttp://www.shnenglu.com/gtwdaizi/articles/49177.html#Feedback0http://www.shnenglu.com/gtwdaizi/comments/commentRss/49177.htmlhttp://www.shnenglu.com/gtwdaizi/services/trackbacks/49177.html
    GetCurrentTime()只和16位版本的windows兼容Q在32位windows下最好用gettickcount();

2. GetLocalTime()

    GetLocalTime()在不同的机器中会有不同的l果Q这和你在控刉板中的时|有? 该函数是获取的系l当前所属时区的旉, 比如? 在北京时? 那么获取的该旉的时?

3. GetSystemTime()
    
     GetSystemTime()获取的格林尼L? 是全球标准时?
      
      SYSTEMTIME stUTC;
      GetSystemTime(&stUTC);
      TCHAR chBuf[nBufSize];
      wsprintf(chBuf,_T("UTC: %u/%u/%u %u:%u:%u:%u %d\r\n"),             
                  stUTC.wYear, stUTC.wMonth, stUTC.wDay,
                  stUTC.wHour, stUTC.wMinute, stUTC.wSecond,
                  stUTC.wMilliseconds,stUTC.wDayOfWeek);

4. GetTickCount()

     GetTickCount()获取的是从设备开机后的毫U数. 不包括系l的挂v旉.

      主要的应?
          dwOldTime = GetTickCount();
          DoSomeThing();
          dwTimeElapsed = GetTickCount() - dwOldTime;
      获取某段E序执行所需的时?

5. 更好的办法:“now函数”
    例如Qformatdatetime('yyyy ''q?' m ''?' d ''?'dddd '+'hh:mm:ssAM/PM',now);
    输出l果Q?2001q??日星期一19Q?5Q?0 PM

]]>
VC 中clw、ncb、aps文g的作?/title><link>http://www.shnenglu.com/gtwdaizi/articles/43370.html</link><dc:creator>郭天?/dc:creator><author>郭天?/author><pubDate>Thu, 28 Feb 2008 01:13:00 GMT</pubDate><guid>http://www.shnenglu.com/gtwdaizi/articles/43370.html</guid><wfw:comment>http://www.shnenglu.com/gtwdaizi/comments/43370.html</wfw:comment><comments>http://www.shnenglu.com/gtwdaizi/articles/43370.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/gtwdaizi/comments/commentRss/43370.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/gtwdaizi/services/trackbacks/43370.html</trackback:ping><description><![CDATA[<div id="yiommgy" class=tit> </div> <table style="TABLE-LAYOUT: fixed"> <tbody> <tr> <td> <div id="aymqeog" class=cnt> <p><br>.clw文g记录了类的信息,如果classView中某个类不见了,重新生成该文件就可以了,ҎQ删除此文gQ点?#8220;建立cd?#8221;Q根据提C入工E名U就可以了;</p> <p><br>.ncb文g记录了类的提CZ息,如果cȝ成员函数和变量的提示不见了,重新生成该文件即可,Ҏ同上Q?<br><br>.aps文g记录了资源信息,要利用现成的资源Q需要修?个文Ӟ.rc文gQResource.h文g?aps文gQ?aps直接删除后,q入E序QVC会自动生成?/p> </div> </td> </tr> </tbody> </table> <img src ="http://www.shnenglu.com/gtwdaizi/aggbug/43370.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/gtwdaizi/" target="_blank">郭天?/a> 2008-02-28 09:13 <a href="http://www.shnenglu.com/gtwdaizi/articles/43370.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CString 操作指南http://www.shnenglu.com/gtwdaizi/articles/42953.html郭天?/dc:creator>郭天?/author>Tue, 19 Feb 2008 09:30:00 GMThttp://www.shnenglu.com/gtwdaizi/articles/42953.htmlhttp://www.shnenglu.com/gtwdaizi/comments/42953.htmlhttp://www.shnenglu.com/gtwdaizi/articles/42953.html#Feedback0http://www.shnenglu.com/gtwdaizi/comments/commentRss/42953.htmlhttp://www.shnenglu.com/gtwdaizi/services/trackbacks/42953.html原文出处Q?a target=_blank>codeprojectQCString Management


通过阅读本文你可以学习如何有效地使用 CString?br>
  CString 是一U很有用的数据类型。它们很大程度上化了MFC中的许多操作Q得MFC在做字符串操作的时候方便了很多。不怎样Q用CString有很多特D的技巧,特别是对于纯C背景下走出来的程序员来说有点难以学习。这文章就来讨些技巧?br>  使用CString可以让你对字W串的操作更加直截了当。这文章不是CString的完全手册,但囊括了大部分常见基本问题?br>
q篇文章包括以下内容Q?

  1. CString 型{化成 int ?/font>

  2. char* 转化?CString
  3. CString 转化?char* 之一Q用LPCTSTR强制转化
  4. CString 转化?char* 之二Q用CString对象的GetBufferҎ
  5. CString 转化?char* 之三: 和控件的接口
  6. BSTR 型{化成 CString ?/font>Q?
  7. CString 和时对?/font>Q?
  8. 1?strong>

    要比用下面的Ҏ好得多:

    char gray[] = "Gray";char cat[] = "Cat";char * graycat = malloc(strlen(gray) + strlen(cat) + 1);strcpy(graycat, gray);strcat(graycat, cat);

    2?strong>格式化字W串

      与其?sprintf() 函数?wsprintf() 函数来格式化一个字W串Q还不如?CString 对象的Format()ҎQ?/p>

    CString s;s.Format(_T("The total is %d"), total);

      用这U方法的好处是你不用担心用来存放格式化后数据的缓冲区是否_大,q些工作由CStringcL你完成?br>  格式化是一U把其它不是字符串类型的数据转化为CStringcd的最常用技巧,比如Q把一个整数{化成CStringcdQ可用如下方法:

    CString s;s.Format(_T("%d"), total);

      我LҎ的字W串使用_T()宏,q是Z让我的代码至有Unicode的意识,当然Q关于Unicode的话题不在这文章的讨论范围。_T()宏在8位字W环境下是如下定义的Q?/p>

    #define _T(x) x // 非Unicode版本Qnon-Unicode versionQ?/pre>
    

    而在Unicode环境下是如下定义的:

    #define _T(x) L##x // Unicode版本QUnicode versionQ?/pre>
    

    所以在Unicode环境下,它的效果q当于Q?/p>

    s.Format(L"%d", total);

      如果你认Z的程序可能在Unicode的环境下q行Q那么开始在意用 Unicode ~码。比如说Q不要用 sizeof() 操作W来获得字符串的长度Q因为在Unicode环境下就会有2倍的误差。我们可以用一些方法来隐藏Unicode的一些细节,比如在我需要获得字W长度的时候,我会用一个叫做DIM的宏Q这个宏是在我的dim.h文g中定义的Q我会在我写的所有程序中都包含这个文Ӟ

    #define DIM(x) ( sizeof((x)) / sizeof((x)[0]) )
      q个宏不仅可以用来解决Unicode的字W串长度的问题,也可以用在编译时定义的表gQ它可以获得表格的项敎ͼ如下Q?br>
    class Whatever { ... };Whatever data[] = {   { ... },    ...   { ... },};for(int i = 0; i < DIM(data); i++) // 扫描表格L匚wV?/pre>
      q里要提醒你的就是一定要注意那些在参C需要真实字节数的API函数调用Q如果你传递字W个数给它,它将不能正常工作。如下:
    
    TCHAR data[20];lstrcpyn(data, longstring, sizeof(data) - 1); // WRONG!lstrcpyn(data, longstring, DIM(data) - 1); // RIGHTWriteFile(f, data, DIM(data), &bytesWritten, NULL); // WRONG!WriteFile(f, data, sizeof(data), &bytesWritten, NULL); // RIGHT

    造成以上原因是因为lstrcpyn需要一个字W个C为参敎ͼ但是WriteFile却需要字节数作ؓ参数?br>同样需要注意的是有时候需要写出数据的所有内宏V如果你仅仅只想写出数据的真实长度,你可能会认ؓ你应该这样做Q?/p>

    WriteFile(f, data, lstrlen(data), &bytesWritten, NULL); // WRONG

    但是在Unicode环境下,它不会正常工作。正的做法应该是这P

    WriteFile(f, data, lstrlen(data) * sizeof(TCHAR), &bytesWritten, NULL); // RIGHT

      因ؓWriteFile需要的是一个以字节为单位的长度。(可能有些Z?#8220;在非Unicode的环境下q行q行代码Q就意味着L在做一个多余的?操作Q这样不会降低程序的效率吗?”q种x是多余的Q你必须要了解编译器实际上做了什么,没有哪一个C或C++~译器会把这U无聊的?操作留在代码中。在Unicode环境下运行的时候,你也不必担心那个?操作会降低程序的效率Q记住,q只是一个左UM位的操作而已Q编译器也很乐意Z做这U替换。)
      使用_T宏ƈ不是意味着你已l创Z一个Unicode的程序,你只是创Z一个有Unicode意识的程序而已。如果你在默认的8-bit模式下编译你的程序的话,得到的将是一个普通的8-bit的应用程序(q里?-bit指的只是8位的字符~码Qƈ不是?位的计算机系l)Q当你在Unicode环境下编译你的程序时Q你才会得到一个Unicode的程序。记住,CString ?Unicode 环境下,里面包含的可都是16位的字符哦?br>
    3?strong>

    4?strong>

    或者这P

    CString graycat("Gray" + "Cat");

      事实上,~译器将抱怨上面的q些试。ؓ什么呢Q因为针对CString ?LPCTSTR数据cd的各U各Ll合Q?#8220; +” q算W?被定义成一个重载操作符。而不是两?LPCTSTR 数据cdQ它是底层数据类型。你不能对基本数据(?int、char 或?char*Q类型重?C++ 的运符。你可以象下面这样做Q?/p>

    CString graycat = CString("Gray") + CString("Cat");

    或者这P

    CString graycat = CString("Gray") + "Cat";

    研究一番就会发玎ͼ“ +”L使用在至有一?CString 对象和一?LPCSTR 的场合?br>
    注意Q编写有 Unicode 意识的代码L一件好事,比如Q?/p>

    CString graycat = CString(_T("Gray")) + _T("Cat");

    q将使得你的代码可以直接UL?br>
    char* 转化?CString

      现在你有一?char* cd的数据,或者说一个字W串。怎么样创?CString 对象呢?q里有一些例子:

    char * p = "This is a test";

    或者象下面q样更具?Unicode 意识Q?/p>

    TCHAR * p = _T("This is a test")

    ?/p>

    LPTSTR p = _T("This is a test");

    你可以用下面Q意一U写法:

    CString s = "This is a test"; // 8-bit onlyCString s = _T("This is a test"); // Unicode-awareCString s("This is a test"); // 8-bit onlyCString s(_T("This is a test")); // Unicode-awareCString s = p;CString s(p);

      用这些方法可以轻村ְ帔R字符串或指针转换?CString。需要注意的是,字符的赋值L被拷贝到 CString 对象中去的,所以你可以象下面这h作:

    TCHAR * p = _T("Gray");CString s(p);p = _T("Cat");s += p;

    l果字符串肯定是“GrayCat”?br>
    CString c还有几个其它的构造函敎ͼ但是q里我们不考虑它,如果你有兴趣可以自己查看相关文档?br>
    事实上,CString cȝ构造函数比我展C的要复杂,比如Q?/p>

    CString s = "This is a test"; 

      q是很草率的~码Q但是实际上它在 Unicode 环境下能~译通过。它在运行时调用构造函数的 MultiByteToWideChar 操作?8 位字W串转换?16 位字W串。不怎样Q如?char * 指针是网l上传输?8 位数据,q种转换是很有用的?br>
    CString 转化?char* 之一Q?/strong>强制cd转换?LPCTSTRQ?br>
      q是一U略微硬性的转换Q有?#8220;正确”的做法,Z在认识上q存在许多؜乱,正确的用方法有很多Q但错误的用方法可能与正确的用方法一样多?br>  我们首先要了?CString 是一U很Ҏ?C++ 对象Q它里面包含了三个|一个指向某个数据缓冲区的指针、一个是该缓冲中有效的字W记C及一个缓冲区长度?有效字符数的大小可以是从0到该~冲最大长度值减1之间的Q何数Q因为字W串l尾有一个NULL字符Q。字W记数和~冲区长度被巧妙隐藏?br>  除非你做一些特D的操作Q否则你不可能知道给CString对象分配的缓冲区的长度。这P即你获得了?~冲的地址Q你也无法更改其中的内容Q不能截短字W串Q也 l对没有办法加长它的内容Q否则第一旉׃看到溢出?br>  LPCTSTR 操作W(或者更明确地说是 TCHAR * 操作W)?CString cM被重载了Q该操作W的定义是返回缓冲区的地址Q因此,如果你需要一个指?CString ?字符串指针的话,可以q样做:

     

    CString s("GrayCat");LPCTSTR p = s;

      它可以正地q行。这是由C语言的强制类型{化规则实现的。当需要强制类型{化时QC++规测容许q种选择。比如,你可以将QQҎQ定义ؓ某个复?Q有一ҎQҎQ进行强制类型{换后只返回该复数的第一个QҎQ也是其实部)。可以象下面q样Q?/p>

    Complex c(1.2f, 4.8f);float realpart = c;

    如果(float)操作W定义正的话,那么实部的的值应该是1.2?br>  q种强制转化适合所有这U情况,例如QQ何带?LPCTSTR cd参数的函数都会强制执行这U{换?于是Q你可能有这样一个函敎ͼ也许在某个你买来的DLL中)Q?/p>

    BOOL DoSomethingCool(LPCTSTR s);

    你象下面q样调用它:

    CString file("c:\\myfiles\\coolstuff")BOOL result = DoSomethingCool(file);

      它能正确q行。因?DoSomethingCool 函数已经说明了需要一?LPCTSTR cd的参敎ͼ因此 LPCTSTR 被应用于该参敎ͼ?MFC 中就是返回的串地址?br>
    如果你要格式化字W串怎么办呢Q?/p>

    CString graycat("GrayCat");CString s;s.Format("Mew! I love %s", graycat);

      注意׃在可变参数列表中的|在函数说明中是以“...”表示的)q没有隐含一个强制类型{换操作符。你会得C么结果呢Q?br>  一个o人惊讶的l果Q我们得到的实际l果串是Q?/p>

    "Mew! I love GrayCat"?/pre>
    

      因ؓ MFC 的设计者们在设?CString 数据cd旉常小心, CString cd表达式求值后指向了字W串Q所以这里看不到M?Format ?sprintf 中的强制cd转换Q你仍然可以得到正确的行为。描q?CString 的附加数据实际上?CString 名义地址之后?br>  有一件事情你是不能做的,那就是修改字W串。比如,你可能会试?#8220;,”代替“.”Q不要做q样的,如果你在乎国际化问题Q你应该使用十进制{换的 National Language Support Ҏ,Q,下面是个单的例子Q?/p>

    CString v("1.00"); // 货币金额Q两位小数LPCTSTR p = v;p[lstrlen(p) - 3] = '','';

      q时~译器会报错Q因Z赋g一个常量串。如果你做如下尝试,~译器也会错Q?/p>

    strcat(p, "each");

      因ؓ strcat 的第一个参数应该是 LPTSTR cd的数据,而你却给了一?LPCTSTR?br>
      不要试图钻这个错误消息的牛角,q只会你自己陷入麻烦!

      原因是缓冲有一个计敎ͼ它是不可存取的(它位?CString 地址之下的一个隐藏区域)Q如果你改变q个Ԍ~冲中的字符计数不会反映所做的修改。此外,如果字符串长度恰好是该字W串物理限制的长度(梢后q会讲到q个问题Q,那么扩展该字W串改写缓冲以外的M数据Q那是你无权q行写操作的内存Q不对吗Q)Q你会毁换坏不属于你的内存。这是应用程序真正的M处方?/p>

    CString转化成char* 之二Q?/strong>使用 CString 对象?GetBuffer ҎQ?br>
      如果你需要修?CString 中的内容Q它有一个特D的Ҏ可以使用Q那是 GetBufferQ它的作用是q回一个可写的~冲指针?如果你只是打修改字W或者截短字W串Q你完全可以q样做:

    CString s(_T("File.ext"));LPTSTR p = s.GetBuffer();LPTSTR dot = strchr(p, ''.''); // OK, should have used s.Find...if(p != NULL)*p = _T(''\0'');s.ReleaseBuffer();

      q是 GetBuffer 的第一U用法,也是最单的一U,不用l它传递参敎ͼ它用默认?0Q意思是Q?#8220;l我q个字符串的指针Q我保证不加长它”。当你调?ReleaseBuffer Ӟ字符串的实际长度会被重新计算Q然后存?CString 对象中?br>  必须一点,?GetBuffer ?ReleaseBuffer 之间q个范围Q一定不能用你要操作的q个~冲?CString 对象的Q何方法。因?ReleaseBuffer 被调用之前,?CString 对象的完整性得不到保障。研I以下代码:

    CString s(...);LPTSTR p = s.GetBuffer();//... q个指针 p 发生了很多事情int n = s.GetLength(); // 很糟D!!!!! 有可能给出错误的{案!!!s.TrimRight(); // 很糟!!!!! 不能保证能正常工?!!!s.ReleaseBuffer(); // 现在应该 OKint m = s.GetLength(); // q个l果可以保证是正的。s.TrimRight(); // 正常工作?/pre>
    

      假设你想增加字符串的长度Q你首先要知道这个字W串可能会有多长Q好比是声明字符串数l的时候用Q?/p>

    char buffer[1024];

    表示 1024 个字W空间以让你做M惛_得事情。在 CString 中与之意义相{的表示法:

    LPTSTR p = s.GetBuffer(1024);

      调用q个函数后,你不仅获得了字符串缓冲区的指针,而且同时q获得了长度臛_?1024 个字W的I间Q注意,我说的是“字符”Q而不?#8220;字节”Q因?CString 是以隐含方式感知 Unicode 的)?br>  同时Q还应该注意的是Q如果你有一个常量串指针Q这个串本n的D存储在只d存中Q如果试囑֭储它Q即使你已经调用?GetBuffer Qƈ获得一个只d存的指针Q存入操作会p|Qƈ报告存取错误。我没有?CString 上证明这一点,但我看到q大把的 C E序员经常犯q个错误?br>  C E序员有一个通病是分配一个固定长度的~冲Q对它进?sprintf 操作Q然后将它赋值给一?CStringQ?/p>

    char buffer[256];sprintf(buffer, "%......", args, ...); // ... 部分省略许多l节CString s = buffer;

    虽然更好的Ş式可以这么做Q?/p>

    CString s;s.Format(_T("%...."), args, ...);

    如果你的字符串长度万一过 256 个字W的时候,不会破坏堆栈?br>
      另外一个常见的错误是:既然固定大小的内存不工作Q那么就采用动态分配字节,q种做法弊端更大Q?/p>

    int len = lstrlen(parm1) + 13  lstrlen(parm2) + 10 + 100;char * buffer = new char[len];sprintf(buffer, "%s is equal to %s, valid data", parm1, parm2);CString s = buffer;......delete [] buffer;

    它可以能被简单地写成Q?/p>

    CString s;s.Format(_T("%s is equal to %s, valid data"), parm1, parm2);

      需要注?sprintf 例子都不?Unicode qA的,管你可以?tsprintf 以及?_T() 来包围格式化字符Ԍ但是基本 思\仍然是在走弯路,q这样很Ҏ出错?br>
    CString to char * 之三Q?/strong>和控件的接口Q?br>
      我们l常需要把一?CString 的g递给一个控Ӟ比如QCTreeCtrl。MFC为我们提供了很多便利来重载这个操作,但是 在大多数情况下,你?#8220;原始”形式的更斎ͼ因此需要将墨某个串指针存储?TVINSERTITEMSTRUCT l构?TVITEM 成员中。如下:

    TVINSERTITEMSTRUCT tvi;CString s;// ... 为s赋一些倹{tvi.item.pszText = s; // Compiler yells at you here// ... 填写tvi的其他域HTREEITEM ti = c_MyTree.InsertItem(&tvi);

      Z么编译器会报错呢Q明明看h很完的用法啊!但是事实上如果你看看 TVITEM l构的定义你׃明白Q在 TVITEM l构?pszText 成员的声明如下:

    LPTSTR pszText;int cchTextMax;

      因此Q赋g是赋l一?LPCTSTR cd的变量,而且~译器无法知道如何将赋D句右边强制{换成 LPCTSTR。好吧,你说Q那我就Ҏq样Q?/p>

    tvi.item.pszText = (LPCTSTR)s; //~译器依然会报错?/pre>
    

      ~译器之所以依然报错是因ؓ你试图把一?LPCTSTR cd的变量赋值给一?LPTSTR cd的变量,q种操作在C或C++中是被禁止的。你不能用这U方?来滥用常量指针与非常量指针概念,否则Q会Cؕ~译器的优化机制Q之不知如何优化你的程序。比如,如果你这么做Q?/p>

    const int i = ...;//... do lots of stuff... = a[i]; // usage 1// ... lots more stuff... = a[i]; // usage 2

      那么Q编译器会以为既?i ?const Q所?usage1和usage2的值是相同的,q且它甚臌事先计算?usage1 处的 a[i] 的地址Q然后保留着在后面的 usage2 处用,而不是重新计。如果你按如下方式写的话Q?/p>

    const int i = ...;int * p = &i;//... do lots of stuff... = a[i]; // usage 1// ... lots more stuff(*p)++; // mess over compiler''s assumption// ... and other stuff... = a[i]; // usage 2

      ~译器将认ؓ i 是常量,从?a[i] 的位|也是常量,q样间接地破坏了先前的假设。因此,你的E序会?debug ~译模式Q没有优化)?release ~译模式Q完全优化)中反映出不同的行为,q种情况可不好,所以当你试图把指向 i 的指针赋值给一?可修改的引用Ӟ会被~译器诊断ؓq是一U伪造。这是Z么(LPCTSTRQ强制类型{化不起作用的原因?br>  Z么不把该成员声明?LPCTSTR cd呢?因ؓq个l构被用于读写控件。当你向控g写数据时Q文本指针实际上被当?LPCTSTRQ而当你从控gL?Ӟ你必L一个可写的字符丌Ӏ这个结构无法区分它是用来读q是用来写?br>
    因此Q你会常常在我的代码中看到如下的用法Q?/p>

    tvi.item.pszText = (LPTSTR)(LPCTSTR)s;

      它把 CString 强制cd转化?LPCTSTRQ也是说先获得改字W串的地址Q然后再强制cd转化?LPTSTRQ以便可以对之进行赋值操作?注意q只有在使用 Set ?Insert 之类的方法才有效Q如果你试图获取数据Q则不能q么做?br>  如果你打获取存储在控g中的数据Q则ҎE有不同Q例如,Ҏ?CTreeCtrl 使用 GetItem ҎQ我惌取项目的文本。我知道q些 文本的长度不会超q?MY_LIMITQ因此我可以q样写:

    TVITEM tvi;// ... assorted initialization of other fields of tvitvi.pszText = s.GetBuffer(MY_LIMIT);tvi.cchTextMax = MY_LIMIT;c_MyTree.GetItem(&tvi);s.ReleaseBuffer();

      可以看出来,其实上面的代码对所有类型的 Set Ҏ都适用Q但是ƈ不需要这么做Q因为所有的c?Set ҎQ包?InsertҎQ不会改变字W串的内宏V但是当你需要写 CString 对象Ӟ必须保证~冲是可写的Q这正是 GetBuffer 所做的事情。再ơ强调: 一旦做了一?GetBuffer 调用Q那么在调用 ReleaseBuffer 之前不要对这?CString 对象做Q何操作?br>
    5?strong> 6?strong>

      对于单个?BSTR 串来_q种用法可以工作得很好,q是因ؓ CString 有一个特D的构造函CLPCWSTRQBSTR正是q种cdQ?为参敎ͼq将它{化成 ANSI cd。专门检查是必须的,因ؓ BSTR 可能为空|?CString 的构造函数对?NULL 值情况考虑的不是很周到Q(感谢 Brian Ross 指出q一?Q。这U用法也只能处理包含 NUL l结字符的单字符Ԍ如果要{化含有多?NULL 字符 Ԍ你得额外做一些工作才行。在 CString 中内嵌的 NULL 字符通常表现不尽如h意,应该量避免?br>  Ҏ C/C++ 规则Q如果你有一?LPWSTRQ那么它别无选择Q只能和 LPCWSTR 参数匚w?br>
    ?Unicode 模式下,它的构造函数是Q?/p>

    CString::CString(LPCTSTR);

    正如上面所表示的,?ANSI 模式下,它有一个特D的构造函敎ͼ

    CString::CString(LPCWSTR); 

      它会调用一个内部的函数?Unicode 字符串{换成 ANSI 字符丌Ӏ(在Unicode模式下,有一个专门的构造函敎ͼ该函数有一个参数是LPCSTRcd——一??ANSI 字符?指针Q该函数它加宽?Unicode 的字W串Q)再次Q一定要?BSTR 的值是否ؓ NULL?br>  另外q有一个问题,正如上文提到的:BSTRs可以含有多个内嵌的NULL字符Q但?CString 的构造函数只能处理某个串中单?NULL 字符?也就是说Q如果串中含有嵌入的 NUL字节QCString 会计算出错误的串长度。你必须自己处理它。如果你看看 strcore.cpp 中的构造函敎ͼ你会发现 它们都调用了lstrlenQ也是计算字符串的长度?br>  注意?Unicode ?ANSI 的{换用带专门参数?::WideCharToMultiByteQ如果你不想使用q种默认的{换方式,则必ȝ写自q转化代码?br>  如果你在 UNICODE 模式下编译代码,你可以简单地写成Q?br>

    CString convert(BSTR b){    if(b == NULL)        return CString(_T(""));    CString s(b); // in UNICODE mode    return s;}
      如果?ANSI 模式Q则需要更复杂的过E来转换。注意这个代码用与 ::WideCharToMultiByte 相同的参数倹{所以你 只能在想要改变这些参数进行{换时使用该技术。例如,指定不同的默认字W,不同的标志集{?
    CString convert(BSTR b){    CString s;    if(b == NULL)       return s; // empty for NULL BSTR#ifdef UNICODE    s = b;#else    LPSTR p = s.GetBuffer(SysStringLen(b) + 1);     ::WideCharToMultiByte(CP_ACP,            // ANSI Code Page                          0,                 // no flags                          b,                 // source widechar string                          -1,                // assume NUL-terminated                          p,                 // target buffer                          SysStringLen(b)+1, // target buffer length                          NULL,              // use system default char                          NULL);             // don''t care if default used    s.ReleaseBuffer();#endif    return s;}
      我ƈ不担心如?BSTR 包含没有映射?8 位字W集?Unicode 字符时会发生什么,因ؓ我指定了::WideCharToMultiByte 的最后两个参Cؓ NULL。这是你可能需要改变的地方?

    7?strong>
    8?strong>载入字符串表资源


      如果你想创徏一个容易进行语a版本UL的应用程序,你就不能在你的源代码中直接包含本土语a字符?Q下面这些例子我用的语言都是pQ因为我的本土语是英语)Q比如下面这U写法就很糟Q?
    CString s = "There is an error";

      你应该把你所有特定语a的字W串单独摆放Q调试信息、在发布版本中不出现的信息除外)。这意味着向下面这样写比较好:

    s.Format(_T("%d - %s"), code, text);

      在你的程序中Q文字字W串不是语言敏感的。不怎样Q你必须很小心,不要使用下面q样的串Q?/p>

    // fmt is "Error in %s file %s"http:// readorwrite is "reading" or "writing"s.Format(fmt, readorwrite, filename); 

      q是我的切n体会。在我的W一个国际化的应用程序中我犯了这个错误,管我懂徯Q知道在徯的语法中动词攑֜句子的最后面Q我们的德国斚w的发行hq是苦苦的抱怨他们不得不提取那些不可思议的d语错误提CZ息然后重新格式化以让它们能正常工作。比较好的办法(也是我现在用的办法Q是使用两个字符Ԍ一个用 于读Q一个用于写Q在使用时加载合适的版本Q得它们对字符串参数是非敏感的。也是说加载整个格式,而不是加载串“reading”Q?#8220;writing”Q?/p>

    // fmt is "Error in reading file %s"http:// "Error in writing file %s"s.Format(fmt, filename);

      一定要注意Q如果你有好几个地方需要替换,你一定要保证替换后句子的l构不会出现问题Q比如在p中,可以是主?宾语Q主?谓语Q动?宾语的结构等{?br>  在这里,我们q不讨论 FormatMessageQ其实它?sprintf/Format q要有优势,但是不太Ҏ和CString l合使用。解册U问题的办法是我们按照参数出现在参数表中的位置l参数取名字Q这样在你输出的时候就不会把他们的位置排错了?br>  接下来我们讨论我们这些独立的字符串放在什么地斏V我们可以把字符串的值放入资源文件中的一个称?STRINGTABLE 的段中。过E如下:首先使用 Visual Studio 的资源编辑器创徏一个字W串Q然后给每一个字W串取一个IDQ一般我们给它取名字都以 IDS_开头。所以如果你有一个信息,你可以创Z个字W串资源然后取名?IDS_READING_FILEQ另外一个就取名?IDS_WRITING_FILE。它们以下面的Ş式出现在你的 .rc 文g中:

    STRINGTABLEIDS_READING_FILE "Reading file %s"IDS_WRITING_FILE "Writing file %s"END

    注意Q?/strong>q些资源都以 Unicode 的格式保存,不管你是在什么环境下~译。他们在Win9xpȝ上也是以Unicode 的Ş式存在,虽然 Win9x 不能真正处理 Unicode?br>然后你可以这样用这些资源:
    // 在用资源串表之前,E序是这样写的:

       CString fmt;      if(...)        fmt = "Reading file %s";     else       fmt = "Writing file %s";  ...    // much later  CString s;  s.Format(fmt, filename); 
    // 使用资源串表之后Q程序这样写Q?
        CString fmt;        if(...)           fmt.LoadString(IDS_READING_FILE);        else           fmt.LoadString(DS_WRITING_FILE);    ...      // much later    CString s;    s.Format(fmt, filename);
      现在Q你的代码可以移植到M语言中去。LoadString Ҏ需要一个字W串资源?ID 作ؓ参数Q然后它?STRINGTABLE 中取出它对应的字W串Q赋值给 CString 对象?CString 对象的构造函数还有一个更加聪明的特征可以?STRINGTABLE 的用。这个用法在 CString::CString 的文档中没有指出Q但是在 构造函数的CZE序中用了。(Z么这个特性没有成为正式文档的一部分Q而是攑֜了一个例子中Q我C得了Q)——?strong>译者注
    Q从q句话看Q作者可能是CString的设计者。其实前面还有一句类似的话。说他没有对使用GetBuffer(0)获得的指针指向的地址是否可读做有效性检?】。这个特征就是:如果你将一个字W串资源的ID强制cd转换?LPCTSTRQ将会隐含调?LoadString。因此,下面两个构造字W串的例子具有相同的效果Q而且?ASSERT 在debug模式下不会被触发Q?
    CString s;s.LoadString(IDS_WHATEVER);CString t( (LPCTSTR)IDS_WHATEVER );ASSERT(s == t);//不会被触发,说明s和t是相同的?/pre>
    

      现在Q你可能会想Q这怎么可能工作呢?我们怎么能把 STRINGTABLE ID 转化成一个指针呢Q很单:所有的字符?ID 都在1~65535q个范围内,也就是说Q它所有的高位都是0Q而我们在E序中所使用的指针是不可能小?5535的,因ؓE序的低 64K 内存永远也不可能存在的,如果你试图访?x00000000?x0000FFFF之间的内存,会引发一个内存越界错误。所以说1~65535的g可能是一个内存地址Q所以我们可以用q些值来作ؓ字符串资源的ID?br>  我們֐于?MAKEINTRESOURCE 宏显式地做这U{换。我认ؓq样可以让代码更加易于阅诅R这是个只适合?MFC 中用的标准宏。你要记住,大多数的Ҏ卛_以接受一?UINT 型的参数Q也可以接受一?LPCTSTR 型的参数Q这是依?C++ 的重载功能做到的。C++重蝲函数带来?弊端是造成所有的强制cd转化都需要显C声明。同P你也可以l很多种l构只传递一个资源名?/p>

    CString s;s.LoadString(IDS_WHATEVER);CString t( MAKEINTRESOURCE(IDS_WHATEVER));ASSERT(s == t);

      告诉你吧Q我不仅只是在这里鼓吹,事实上我也是q么做的。在我的代码中,你几乎不可能扑ֈ一个字W串Q当Ӟ那些只是偶然在调试中出现的或者和语言无关的字W串除外?br>
    9?strong>

    char* szName = GetName().GetBuffer(20);RegSetValueEx(hKey, "Name", 0, REG_SZ,              (CONST BYTE *) szName,             strlen (szName + 1));

    q个 Name 字符串的长度于 20Q所以我不认为是 GetBuffer 的参数的问题?br>
    真让人困惑,请帮帮我?br>
    亲爱?FrustratedQ?br>
    你犯了一个相当微妙的错误Q聪明反被聪明误Q正的代码应该象下面这P

    CString Name = GetName();RegSetValueEx(hKey, _T("Name"), 0, REG_SZ,                     (CONST BYTE *) (LPCTSTR)Name,                    (Name.GetLength() + 1) * sizeof(TCHAR));
      Z么我写的代码能行而你写的有问题呢?主要是因为当你调?GetName 时返回的 CString 对象是一个时对象。参见:《C++ Reference manual?#167;12.2
      在一些环境中Q编译器有必要创Z个时对象,q样引入临时对象是依赖于实现的。如果编译器引入的这个时对象所属的cL构造函数的话,~译器要保q个cȝ构造函数被调用。同LQ如果这个类声明有析构函数的话,也要保证q个临时对象的析构函数被调用?br>  ~译器必M证这个时对象被销毁了。被销毁的切地点依赖于实?....q个析构函数必须在退出创临时对象的范围之前被调用?br>  大部分的~译器是q样设计的:在时对象被创徏的代码的下一个执行步骤处隐含调用q个临时对象的析构函敎ͼ实现hQ一般都是在下一个分号处。因此,q个 CString 对象?GetBuffer 调用之后p析构了(Z提一句,你没有理q GetBuffer 函数传递一个参敎ͼ而且没有使用ReleaseBuffer 也是不对的)。所?GetBuffer 本来q回的是指向q个临时对象中字W串的地址的指针,但是当这个时对象被析构后,q块内存p释放了。然?MFC 的调试内存分配器会重Cؓq块内存全部填上 0xDDQ显C出来刚好就?#8220;&Yacute;”W号。在q个时候你向注册表中写数据Q字W串的内容当然全被破坏了?br>  我们不应该立xq个临时对象转化?char* cdQ应该先把它保存C?CString 对象中,q意味着把时对象复制了一份,所以当临时?CString 对象被析构了之后Q这?CString 对象中的g然保存着。这个时候再向注册表中写数据没有问题了?br>  此外Q我的代码是h Unicode 意识的。那个操作注册表的函数需要一个字节大,使用lstrlen(Name+1) 得到的实际结果对?Unicode 字符来说?ANSI 字符要小一半,而且它也不能从这个字W串的第二个字符起开始计,也许你的本意?lstrlen(Name) + 1QOKQ我承认Q我也犯了同L错误Q)。不论如何,?Unicode 模式下,所有的字符都是2个字节大,我们需要处理这个问题。微软的文档令h惊讶地对此保持缄默:REG_SZ 的值究竟是以字节计还是以字符计算呢?我们假设它指的是以字节ؓ单位计算Q你需要对你的代码做一些修Ҏ计算q个字符串所含有的字节大?br>
    10?strong>


      CString 的一个问题是它确实掩藏了一些低效率的东ѝ从另外一个方面讲Q它也确实可以被实现得更加高效,你可能会说下面的代码Q?
    CString s = SomeCString1;s += SomeCString2;s += SomeCString3;s += ",";s += SomeCString4;

    比v下面的代码来Q效率要低多了:

    char s[1024];lstrcpy(s, SomeString1);lstrcat(s, SomeString2);lstrcat(s, SomeString 3);lstrcat(s, ",");lstrcat(s, SomeString4);

      MQ你可能会想Q首先,它ؓ SomeCString1 分配一块内存,然后?SomeCString1 复制到里面,然后发现它要做一个连接,则重新分配一块新的够大的内存,大到能够放下当前的字W串加上SomeCString2Q把内容复制到这块内?Q然后把 SomeCString2 q接到后面,然后释放W一块内存,q把指针重新指向新内存。然后ؓ每个字符串重复这个过E。把q?4 个字W串q接h效率多低啊。事实上Q在很多情况下根本就不需要复制源字符Ԍ?+= 操作W左边的字符Ԍ?br>  ?VC++6.0 中,Release 模式下,所有的 CString 中的~存都是按预定义量子分配的。所谓量子,即确定ؓ 64?28?56 或?512 字节。这意味着除非字符串非帔RQ连接字W串的操作实际上是 strcat l过优化后的版本Q因为它知道本地的字W串应该在什么地方结束,所以不需要寻扑֭W串的结;只需要把内存中的数据拯到指定的地方卛_Q加上重新计字W串的长度。所以它的执行效率和U?C 的代码是一LQ但是它更容易写、更Ҏl护和更Ҏ理解?br>  如果你还是不能确定究竟发生了怎样的过E,L?CString 的源代码Qstrcore.cppQ在?vc98的安装目录的 mfc\src 子目录中。看?ConcatInPlace ҎQ它被在所有的 += 操作W中调用?br>
    啊哈Q难?CString 真的q么"高效"吗?比如Q如果我创徏

    CString cat("Mew!");

      然后我ƈ不是得到了一个高效的、精?个字节大的~冲区(4个字W加一个结束字W)Q系l将l我分配64个字节,而其?9个字节都被浪费了?br>  如果你也是这么想的话Q那么就请准备好接受再教育吧。可能在某个地方某个人给你讲q尽量用少的空间是件好事情。不错,q种说法的确正确Q但是他忽略了事实中一个很重要的方面?br>  如果你编写的是运行在16K EPROMs下的嵌入式程序的话,你有理由量用空_在这U环境下Q它能你的E序更健壮。但是在 500MHz, 256MB的机器上?Windows E序Q如果你q是q么做,它只会比你认为的“低效”的代码运行得更糟?br>  举例来说。字W串的大被认ؓ是媄响效率的首要因素Q字符串尽可能可以提高效率,反之则降低效率,q是大家一贯的x。但是这U想法是不对的,_的内存分配的后果要在E序q行了好几个时后才能体现得出来Q那ӞE序的堆中将充满片的内存,它们太小以至于不能用来做M事,但是他们增加了你E序的内存用量,增加了内存页面交换的ơ数Q当面交换的次数增加到pȝ能够忍受的上限,pȝ则会Z的程序分配更多的面Q直C的程序占用了所有的可用内存。由此可见,虽然内存片是决定效率的ơ要因素Q但正是q些因素实际控制了系l的行ؓQ最l,它损害了pȝ的可靠性,q是令h无法接受的?br>  CQ在 debug 模式下,内存往往是精分配的Q这是ؓ了更好的排错?br>  假设你的应用E序通常需要连l工作好几个月。比如,我常打开 VC++QWordQPowerPointQFrontpageQOutlook ExpressQForté AgentQInternet Explorer和其它的一些程序,而且通常不关闭它们。我曄夜以l日地连l用 PowerPoint 工作了好几天Q反之,如果你不q怸得不使用?Adobe FrameMaker q样的程序的话,你将会体会到可靠性的重要Q这个程序机会每天都要崩?~6ơ,每次都是因ؓ用完了所有的I间q填满我所有的交换面Q。所以精内存分配是不可取的Q它会危及到pȝ的可靠性,q引起应用程序崩溃?br>  按量子的倍数为字W串分配内存Q内存分配器可以回收用q的内存块,通常q些回收的内存块马上可以被其它?CString 对象重新用到Q这样就可以保证片最。分配器的功能加ZQ应用程序用到的内存p可能保持最,q样的程序就可以q行几个星期或几个月而不出现问题?br>  题外话:很多q以前,我们?CMU 写一个交互式pȝ的时候,一些对内存分配器的研究昄出它往往产生很多内存片。Jim MitchellQ现在他?Sun Microsystems 工作Q那时侯他创造了一U内存分配器Q它保留了一个内存分配状늚q行时统计表Q这U技术和当时的主分配器所用的技术都不同Q且较ؓ领先。当一个内存块需要被分割得比某一个值小的话Q他q不分割它,因此可以避免产生太多到什么事都干不了的内存碎片。事实上他在内存分配器中使用了一个Q动指针,他认为:与其让指令做长时间的存取内存操作Q还不如单的忽略那些太小的内存块而只做一些Q动指针的操作。(His observation was that the long-term saving in instructions by not having to ignore unusable small storage chunks far and away exceeded the additional cost of doing a few floating point operations on an allocation operation.Q他是对的?br>  永远不要认ؓ所谓的“最优化”是徏立在每一行代码都高速且节省内存的基上的Q事实上Q高速且节省内存应该是在一个应用程序的整体水^上考虑的。在软g的整体水q上Q只使用最内存的字符串分配策略可能是最p糕的一U方法?br>  如果你认Z化是你在每一行代码上做的那些努力的话Q你应该想一惻I在每一行代码中做的优化很少能真正v作用。你可以看我的另一关于优化问题的文章《Your Worst Enemy for some thought-provoking ideas》?br>  CQ?= q算W只是一U特例,如果你写成下面这P

    CString s = SomeCString1 + SomeCString2 + SomeCString3 + "," + SomeCString4;

    则每一?+ 的应用会造成一个新的字W串被创建和一ơ复制操作?br>
    ȝ

      以上是?CString 的一些技巧。我每天写程序的时候都会用到这些。CString q不是一U很难用的c,但是 MFC 没有很明昄指出q些特征Q需要你自己L索、去发现?br>



    ]]>音频~解码标?/title><link>http://www.shnenglu.com/gtwdaizi/articles/41884.html</link><dc:creator>郭天?/dc:creator><author>郭天?/author><pubDate>Fri, 25 Jan 2008 05:29:00 GMT</pubDate><guid>http://www.shnenglu.com/gtwdaizi/articles/41884.html</guid><wfw:comment>http://www.shnenglu.com/gtwdaizi/comments/41884.html</wfw:comment><comments>http://www.shnenglu.com/gtwdaizi/articles/41884.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/gtwdaizi/comments/commentRss/41884.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/gtwdaizi/services/trackbacks/41884.html</trackback:ping><description><![CDATA[<dd> <div><br><span style="COLOR: red">PCMU(G.711U)<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?4Kbps(90.4)<br>Ҏ:PCMU和PCMA都能提供较好的语韌量,但是它们占用的带宽较高,需?4kbps?br>优点Q语韌量优<br>~点Q占用的带宽较高<br>应用领域Qvoip<br>版税方式QFree<br>备注QPCMU and PCMA都能够达到CD韌Q但是它们消耗的带宽也最?64kbps)。如果网l带宽比较低Q可以选用低比牚w率的编码方法,如G.723或G.729Q这两种~码的方法也能达Cl长途电话的韌Q但是需要很的带宽QG723需?.3/6.3kbpsQG729需?kbpsQ。如果带宽够ƈ且需要更好的语音质量Q就使用PCMU ?PCMAQ甚臛_以用宽带的~码ҎG722(64kbps)Q这可以提供有高保真度的韌?br>                                                                                                             <br><br><span style="COLOR: red">PCMA(G.711A)<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?4Kbps(90.4)<br>Ҏ:PCMU和PCMA都能提供较好的语韌量,但是它们占用的带宽较高,需?4kbps?br>优点Q语韌量优<br>~点Q占用的带宽较高<br>应用领域Qvoip<br>版税方式QFree<br>备注QPCMU and PCMA都能够达到CD韌Q但是它们消耗的带宽也最?64kbps)。如果网l带宽比较低Q可以选用低比牚w率的编码方法,如G.723或G.729Q这两种~码的方法也能达Cl长途电话的韌Q但是需要很的带宽QG723需?.3/6.3kbpsQG729需?kbpsQ。如果带宽够ƈ且需要更好的语音质量Q就使用PCMU ?PCMAQ甚臛_以用宽带的~码ҎG722(64kbps)Q这可以提供有高保真度的韌?/div> <dt>  <dd> <div><br><span style="COLOR: red">ADPCM(自适应差分PCM)<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?2Kbps<br>Ҏ:ADPCM(adaptive difference pulse code modulation)l合了APCM的自适应Ҏ和DPCMpȝ的差分特性,是一U性能比较好的波Ş~码。它的核心想法是Q?br>       ①利用自适应的思想改变量化阶的大小Q即使用的量化?step-size)ȝ码小的差|使用大的量化阶去~码大的差|<br>       ②用过ȝhg下一个输入样本的预测|使实际样本值和预测g间的差值L最?br>优点Q算法复杂度低,压羃比小QCD韌>400kbpsQ,~解码g时最短(相对其它技术)<br>~点Q声韌量一?br>应用领域Qvoip<br>版税方式QFree<br>备注QADPCM (ADPCM Adaptive Differential Pulse Code Modulation), 是一U针?16bit (或者更?) 声音波Ş数据的一U有损压~算? 它将声音中每次采样?16bit 数据?4bit 存储, 所以压~比 1:4. 而压~?解压~算法非常的? 所以是一U低I间消?高质量声韌得的好途径?br>                                                                                                              <br><br><span style="COLOR: red">LPC(Linear Predictive CodingQ线性预编?<br></span>cdQAudio<br>制定者: <br>所需频宽Q?Kbps-4.8Kbps<br>Ҏ:压羃比大Q计量大,韌不高Q廉?br>优点Q压~比?廉h<br>~点Q计量大,语音质量不是很好Q自然度较低<br>应用领域Qvoip<br>版税方式QFree<br>备注Q参数编码又UCؓ声源~码Q是信源信号在频率域或其它正交变换域提取特征参敎ͼq将其变换成数字代码q行传输。译码ؓ其反q程Q将收到的数字序列经变换恢复特征参量Q再Ҏ特征参量重徏语音信号。具体说Q参数编码是通过对语音信L征参数的提取和编码,力图佉K音信号具有尽可能高的准确性,但重ZL波Ş同原语音信号的L形可能会有相当大的差别。如Q线性预编码(LPCQ及其它各种改进型都属于参数~码。该~码比特率可压羃?Kbit/s-4.8Kbit/sQ甚x低,但语韌量只能达C{,特别是自然度较低?/div> <dt>  <dd> <div><br><span style="COLOR: red">CELP(Code Excited Linear PredictionQ码Ȁq性预编?<br></span>cdQAudio<br>制定者:Ƨ洲通信标准协会QETSIQ?br>所需频宽Q??6Kbps的速率<br>Ҏ:改善语音的质量:<br>       ?对误差信可行感觉加权,利用人类听觉的掩蔽特性来提高语音的主观质量;<br>       ②用分数延迟改进基音预测Qɋ音的表达更为准,其改善了女性语音的质量Q?br>       ?使用修正的MSPE准则来寻?“最?#8221;的gq,使得基音周期延迟的外形更为^滑;<br>       ④根据长旉的效率Q调整随机激q量的大小Q提高语音的主观质量Q?nbsp;      ?使用Z信道错误率估计的自适应qx器,在信道误码率较高的情况下也能合成自然度较高的语音?br>       l论Q?br>       ?CELP法在低速率~码环境下可以得Co人满意的压羃效果Q?br>       ②用快速算法,可以有效地降低CELP法的复杂度Q它完全可以实时地实现Q?br>       ③CELP可以成功地对各种不同cd的语音信可行编码,q种适应性对于真实环境,其是背景噪声存在时更ؓ重要?br>优点Q用很低的带宽提供了较清晰的语音<br>~点Q?br>应用领域Qvoip<br>版税方式QFree<br>备注Q?999q欧z通信标准协会QETSIQ推ZZ码激q性预编码(CELPQ的W三代移动通信语音~码标准自适应多速率语音~码器(AMRQ,其中最低速率?.75kb/sQ达到通信质量。CELP 码激q性预编码是Code Excited Linear Prediction的羃写。CELP是近10q来最成功的语音编码算法?br>       CELP语音~码法用线性预提取声道参敎ͼ用一个包含许多典型的Ȁq量的码本作ؓȀ励参敎ͼ每次~码旉在这个码本中搜烦一个最佳的Ȁq量,q个Ȁq量的~码值就是这个序列的码本中的序号?br>       CELP已经被许多语音编码标准所采用Q美国联邦标准FS1016是采用CELP的编码方法,主要用于高质量的H带语音保密通信。CELP (Code-Excited Linear Prediction) q是一个简化的 LPC 法Q以其低比特率著U?(4800-9600Kbps)Q具有很清晰的语韛_质和很高的背景噪韛_疫性。CELP是一U在中低速率上广泛用的语音压羃~码Ҏ?br>                                                                                                          <br><br><span style="COLOR: red">G.711<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?4Kbps<br>Ҏ:法复杂度小Q音质一?br>优点Q算法复杂度低,压羃比小QCD韌>400kbpsQ,~解码g时最短(相对其它技术)<br>~点Q占用的带宽较高<br>应用领域Qvoip<br>版税方式QFree<br>备注Q?0q代CCITT公布的G.711 64kb/s脉冲~码调制PCM?br>                                                                                                            <br><br><span style="COLOR: red">G.721</span><br>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?2Kbps<br>Ҏ:相对于PCMA和PCMUQ其压羃比较高,可以提供2Q?的压~比?br>优点Q压~比?br>~点Q声韌量一?br>应用领域Qvoip<br>版税方式QFree<br>备注Q子带ADPCMQSB-ADPCMQ技术。G.721标准是一个代码{换系l。它使用ADPCM转换技术,实现64 kb/s A律或μ律PCM速率?2 kb/s速率之间的相互{换?/div> <dt>  <dd> <div><br><span style="COLOR: red">G.722</span><br>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?4Kbps<br>Ҏ:G722能提供高保真的语韌?br>优点Q音质好<br>~点Q带宽要求高<br>应用领域Qvoip<br>版税方式QFree<br>备注Q子带ADPCMQSB-ADPCMQ技?br>                                                                                                              <br><br><span style="COLOR: red">G.723(低码率语音编码算?<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?.3Kbps/6.3Kbps<br>Ҏ:语音质量接近良,带宽要求低,高效实现Q便于多路扩展,可利用C5402片内16kRAM实现53coder。达到ITU-TG723要求的语韌量,性能E_。可用于IP电话语音信源~码或高效语韛_~存储?br>优点Q码率低Q带宽要求较。ƈ辑ֈITU-TG723要求的语韌量,性能E_?br>~点Q声韌量一?br>应用领域Qvoip<br>版税方式QFree<br>备注QG.723语音~码器是一U用于多媒体通信Q编码速率?.3kbits/s?.3kbit/s的双码率~码Ҏ。G.723标准是国际电信联盟(ITUQ制定的多媒体通信标准中的一个组成部分,可以应用于IP电话{系l中。其中,5.3kbits/s码率~码器采用多脉冲最大似焉化技术(MPQMLQQ,6.3kbits/s码率~码器采用代数码Ȁq性预技术?br>                                                                                                             <br><br><span style="COLOR: red">G.723.1(双速率语音~码法)<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?.3Kbps(22.9)<br>Ҏ:能够寚w乐和其他音频信号q行压羃和解压羃Q但它对语音信号来说是最优的。G.723.1采用了执行不q箋传输的静韛_~,q就意味着在静x间的比特中加入了h为的噪声。除了预留带宽之外,q种技术发信机的调制解调器保持连l工作,q且避免了蝲波信L旉时断?br>优点Q码率低Q带宽要求较。ƈ辑ֈITU-TG723要求的语韌量,性能E_,避免了蝲波信L旉时断?br>~点Q语韌量一?br>应用领域Qvoip<br>版税方式QFree<br>备注QG.723.1法?ITU-T的应用于低速率多媒体服务中语音或其它音频信L压羃法Q其目标应用pȝ包括H.323、H.324{多媒体通信pȝ 。目前该法已成为IP电话pȝ中的必选算法之一?br>                                                                                                                <br><br><span style="COLOR: red">G.728<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?6Kbps/8Kbps<br>Ҏ:用于IP电话、卫星通信、语韛_储等多个领域。G.728是一U低时g~码器,但它比其它的~码器都复杂Q这是因为在~码器中必须重复?0阶LPC分析。G.728q采用了自适应后置滤L器来提高其性能?br>优点Q后向自适应Q采用自适应后置滤L器来提高其性能<br>~点Q比其它的编码器都复?br>应用领域Qvoip<br>版税方式QFree<br>备注QG.728 16kb/s短g时码本激q性预编码(LD-CELPQ?996qITU公布了G.728 8kb/s的CSQACELP法Q可以用于IP电话、卫星通信、语韛_储等多个领域?6 kbps G.728低时延码Ȁq性预?<br>       G.728是低比特U性预合成分析编码器QG.729和G.723.1Q和后向ADPCM~码器的混合体。G.728是LD-CELP~码器,它一ơ只处理5个样炏V对于低速率Q?6~128 kbpsQ的l合业务数字|(ISDNQ可视电话,G.728是一U徏议采用的语音~码器。由于其后向自适应Ҏ,因此G.728是一U低时g~码器,但它比其它的~码器都复杂Q这是因为在~码器中必须重复?0阶LPC分析。G.728q采用了自适应后置滤L器来提高其性能?/div> <dt>  <dd> <div><br><span style="COLOR: red">G.729<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?Kbps<br>Ҏ:在良好的信道条g下要辑ֈ长话质量Q在有随机比特误码、发生丢失和多ơ{接等情况下要有很好的E_性等。这U语韛_~算法可以应用在很广泛的领域中,包括QP电话、无UK信、数字卫星系l和数字专用U\?br>       G.729法采用“pl构代数码本Ȁq性预编码方?#8221;QCS-ACELPQ算法。这U算法综合了波Ş~码和参数编码的优点Q以自适应预测~码技术ؓ基础Q采用了矢量量化、合成分析和感觉加权{技术?br>       G.729~码器是Z时g应用设计的,它的帧长只有10msQ处理时延也?0msQ再加上5ms的前视,q就使得G.729产生的点到点的时延ؓ25msQ比特率? kbps?br>优点Q语韌量良Q应用领域很q泛Q采用了矢量量化、合成分析和感觉加权Q提供了对丢失和分l丢q隐藏处理机制<br>~点Q在处理随机比特错误斚w性能不好?br>应用领域Qvoip<br>版税方式QFree<br>备注Q国际电信联盟(ITU-TQ于1995q?1月正式通过了G.729?ITU-TG.729也被UC“pl构代数码本Ȁq性预编码方?#8221;(CS-ACELP)Q它是当前较新的一U语韛_~标准。G.729是由国、法国、日本和加拿大的几家著名国际电信实体联合开发的?br>                                                                                                               <br><br><span style="COLOR: red">G.729A<br></span>cdQAudio<br>制定者:ITU-T<br>所需频宽Q?Kbps(34.4)<br>Ҏ:复杂性较G.729低,性能较G.729差?br>优点Q语韌量良Q降低了计算的复杂度以便于实时实玎ͼ提供了对帧丢失和分组丢失的隐藏处理机?br>~点Q性能较G.729?br>应用领域Qvoip<br>版税方式QFree<br>备注Q?6qITU-T又制定了G.729的简化方案G.729AQ主要降低了计算的复杂度以便于实时实玎ͼ因此目前使用的都是G.729A?br>                                                                                                       <br><br><span style="COLOR: red">GIPS<br></span>cdQAudio<br>制定者:瑞典Global IP Sound公司<br>所需频宽Q?br>Ҏ:GIPS技术可Ҏ带宽状况自动调节~码码率Q提供低码率高质量的音频。GIPS的核心技术(|络自适应法Q丢包补偿算法和回声消除法Q可很好地解册韛_gq与回声问题Q带来完音质,提供比电话还清晰的语音通话效果?br>优点Q很好地解决语音延迟与回声问题,带来完美韌Q提供比电话q清晰的语音通话效果<br>~点Q?不是Free<br>应用领域Qvoip<br>版税方式Q每q支付一W用权费用<br>备注QGIPS音频技术是由来自瑞典的全球尖的语韛_理高U技公司--"GLOBAL IP SOUND"提供的专用于互联|的语音压羃引擎pȝ。GIPS技术可Ҏ带宽状况自动调节~码码率Q提供低码率高质量的音频。GIPS的核心技术(|络自适应法Q丢包补偿算法和回声消除法Q可很好地解册韛_gq与回声问题Q带来完音质,提供比电话还清晰的语音通话效果?br>                                                                                                          <br><br><span style="COLOR: red">Apt-X</span><br>cdQAudio<br>制定者:Audio Processing Technology 公司<br>所需频宽Q?0Hz to 22.5 kHzQ?6kbit/s to 576 kbit/s(16 bit 7.5 kHz mono to 24-bit, 22.5kHz stereo)<br>Ҏ:主要用于专业音频领域Q提供高品质的音频。其特点是:<br>       ①采?:1:4的压~与攑֤ҎQ?br>       ②硬件低复杂度;<br>       ③极低的~码延迟Q?br>       ④由单芯片实玎ͼ<br>       ⑤单声道或立体声~解码;<br>       ⑥只需单设备即可实?2.5kHz的双通道立体壎ͼ<br>       ⑦高?8kHz的采样频率;<br>       ⑧容错性好Q?br>       ⑨完整的AUTOSYNC™~解码同步方案;<br>       ⑩低功率消?br>优点Q高品质的音频,g复杂度低Q设备要求低<br>~点Q不是Free<br>应用领域Qvoip<br>版税方式Q一ơ性付?br>备注Q子带ADPCMQSB-ADPCMQ技?/div> <dt>  <dd> <div><br><span style="COLOR: red">NICAM(Near Instantaneous Companded Audio Multiplex 准瞬时压扩音频复?<br></span>cdQAudio<br>制定者:英国BBCq播公司<br>所需频宽Q?28Kbps<br>Ҏ:应用范围及其q泛Q可用它q行立体声或双语q播<br>优点Q应用范围及其广泛,信噪比高Q动态范围宽、音质同CD相媲,故名丽音Q因此NICAM又称Z?br>~点Q不是FreeQ频宽要求高<br>应用领域Qvoip<br>版税方式Q一ơ性付?br>备注QNICAM也称丽音Q它是英文Near-Instantaneously Companded Audio Multiplex的羃写,其含义ؓ准瞬时压扩音频复用,是由英国BBCq播公司开发研I成功的?br>       通俗地说NICAM技术实际上是双声道数字声技术,其应用范围及其广泛,最典型的应用便是电视广播附加双声道数字声技术,利用它进行立体声或双语广播,以充分利用电视频道的频谱资源。这是在常规电视q播的基上无需增加许多投资可以实现的。在q行立体声广播时Q它提高了音频的信号质量Q其接qCD的质量。而且q可以利用NICAM技术进行高速数据广播及其他数据传输的增D服务,q在当今的信息化C会中似乎就昑־ؓ重要了!<br>                                                                                                       <br><br><span style="COLOR: red">MPEG-1 audio layer 1</span><br>cdQAudio<br>制定者:MPEG<br>所需频宽Q?84kbpsQ压~?倍)<br>Ҏ:~码单,用于数字盒式录音带Q?声道QVCD中用的音频压羃Ҏ是MPEG-1层Ⅰ?br>优点Q压~方式相Ҏ域压~技术而言要复杂得多,同时~码效率、声韌量也大幅提高Q编码g时相应增加。可以达?#8220;完全透明”的声韌量(EBU韌标准Q?br>~点Q频宽要求较?br>应用领域Qvoip<br>版税方式QFree<br>备注QMPEG-1声音压羃~码是国际上W一个高保真声音数据压羃的国际标准,它分Z个层ơ:<br>--?(Layer 1)Q编码简单,用于数字盒式录音带<br>--?(Layer 2)Q算法复杂度中等Q用于数字音频广?DAB)和VCD{?br>--?(Layer 3)Q编码复杂,用于互联|上的高质量声音的传输,如MP3音乐压羃10?br>                                                                                                             <br><br><span style="COLOR: red">MUSICAM(MPEG-1 audio layer 2,即MP2)</span><br>cdQAudio<br>制定者:MPEG<br>所需频宽Q?56?92kbpsQ压~??倍)<br>Ҏ:法复杂度中{,用于数字音频q播(DAB)和VCD{,2声道Q而MUSICAM׃光当的复杂程度和优秀的声韌量,在数字演播室、DAB、DVB{数字节目的制作、交换、存储、传送中得到q泛应用?br>优点Q压~方式相Ҏ域压~技术而言要复杂得多,同时~码效率、声韌量也大幅提高Q编码g时相应增加。可以达?#8220;完全透明”的声韌量(EBU韌标准Q?br>~点Q?br>应用领域Qvoip<br>版税方式QFree<br>备注Q同MPEG-1 audio layer 1<br>                                                                                                   <br><br><span style="COLOR: red">MP3(MPEG-1 audio layer 3)<br></span>cdQAudio<br>制定者:MPEG<br>所需频宽Q?28?12kbpsQ压~?0?2倍)<br>Ҏ:~码复杂Q用于互联网上的高质量声音的传输Q如MP3音乐压羃10倍,2声道。MP3是在l合MUSICAM和ASPEC的优点的基础上提出的混合压羃技术,在当时的技术条件下QMP3的复杂度昑־相对较高Q编码不利于实时Q但׃MP3在低码率条g下高水准的声韌量,使得它成Y解压及网l广播的宠儿?br>优点Q压~比高,适合用于互联|上的传?br>~点QMP3?28KBitrate及以下时Q会出现明显的高频丢?br>应用领域Qvoip<br>版税方式QFree<br>备注Q同MPEG-1 audio layer 1<br><br><span style="COLOR: red">MPEG-2 audio layer</span><br>cdQAudio<br>制定者:MPEG<br>所需频宽Q与MPEG-1?Q层2Q层3相同<br>Ҏ:MPEG-2的声韛_~编码采用与MPEG-1声音相同的编译码器,?, ?和层3的结构也相同Q但它能支持5.1声道?.1声道的环l立体声?br>优点Q支?.1声道?.1声道的环l立体声<br>~点Q?br>应用领域Qvoip<br>版税方式Q按个收?br>备注QMPEG-2的声韛_~编码采用与MPEG-1声音相同的编译码器,?, ?和层3的结构也相同Q但它能支持5.1声道?.1声道的环l立体声?/div> <dt>  <dd> <div><br><span style="COLOR: red">AAC(Advanced Audio CodingQ先q音频编?<br></span>cdQAudio<br>制定者:MPEG<br>所需频宽Q?6-128 kbps<br>Ҏ:AAC可以支持1?8路之间Q意数目的音频声道l合、包?5路低频效果声道、配?多语韛_道,以及15路数据。它可同时传?6套节目,每套节目的音频及数据l构可Q意规定?br>       AAC主要可能的应用范围集中在因特|网l传播、数字音频广播,包括卫星直播和数字AM、以及数字电视及影院pȝ{方面。AAC使用了一U非常灵zȝ늼码核心去传输~码频谱数据。具?8 个主要音频通道Q?6 个低频增强通道Q?6 个集成数据流, 16 个配韻I16 U编排?br>优点Q支持多U音频声道组合,提供优质的音?br>~点Q?<br>应用领域Qvoip<br>版税方式Q一ơ性收?br>备注QAAC?997qŞ成国际标准ISO 13818-7。先q音频编码(Advanced Audio Coding--AACQ开发成功,成ؓlMPEG-2音频标准QISO/IEC13818-3Q之后的C代音频压~标准?br>       在MPEG-2制订的早期,本来是想其音频~码部分保持与MPEG-1兼容的。但后来Z适应演播电视的要求而将其定义成Z个可以获得更高质量的多声道音频标准。理所当然圎ͼq个标准是不兼容MPEG-1的,因此被称为MPEG-2 AAC。换句话_从表面上看,要制作和播放AACQ都需要用与MP3完全不同的工兗?br>                                                                                                            <br><br><span style="COLOR: red">Dolby AC-3<br></span>cdQAudio<br>制定者:国杜比公司<br>所需频宽Q?4kbps<br>Ҏ:提供的环l立体声pȝ?个全频带声道加一个超低音声道l成Q?个声道的信息在制作和q原q程中全部数字化Q信息损失很,l节丰富Q具有真正的立体声效果,在数字电视、DVD和家庭媄院中q泛使用?br>优点Q环l立体声Q信息损失很,l节丰富Q具有真正的立体声效?br>~点Q?br>应用领域Qvoip<br>版税方式Q按个收?br>备注Q杜比数字AC-3QDolby Digital AC-3Q:国杜比公司开发的多声道全频带声音~码pȝQ它提供的环l立体声pȝ?个全频带声道加一个超低音声道l成Q?个声道的信息在制作和q原q程中全部数字化Q信息损失很,l节丰富Q具有真正的立体声效果,在数字电视、DVD和家庭媄院中q泛使用?br>                                                                                                           <br><br><span style="COLOR: red">ASPECQAudio Spectral Perceptual Entropy CodingQ?br></span>cdQAudio<br>制定者:AT&T<br>所需频宽Q?4kps<br>Ҏ:音频质量获得显著改善Q不q计复杂度也大大提高,而且在回响、低码率时声韌量严重下降?br>优点Q音频质量获得显著改?br>~点Q计复杂度的提高。块边界影响、预计算复杂度的提高。回响、低码率时声韌量严重下?br>应用领域Qvoip<br>版税方式Q按个收?br>备注Q变换压~技?br>                                                                                                  <br><br><span style="COLOR: red">PACQPerceptual Audio CoderQ?br></span>cdQAudio<br>制定者:AT&T<br>所需频宽Q?4kps<br>Ҏ:音频质量获得显著改善Q不q在回响、低码率时声韌量严重下降?br>优点Q音频质量获得显著改?br>~点Q块边界影响、预回响、低码率时声韌量严重下?br>应用领域Qvoip<br>版税方式Q按个收?br>备注Q变换压~技?br>                                                                                                   <br><br><span style="COLOR: red">HR</span><br>cdQAudio<br>制定者: 飞利?br>所需频宽Q?Kbps<br>Ҏ:以增加GSM|络定w为目?但是会损完韌?׃现在|络频率紧缺,一些大的运营商已经在大城市密集地带开通此方式以增加容量?br>优点Q系l容量大<br>~点Q语韌量差<br>应用领域QGSM<br>版税方式Q按个收?br>备注QHF半速率,是一UGSM语音~码方式?/div> <dt>  <dd> <div><br><span style="COLOR: red">FR<br></span>cdQAudio<br>制定者:飞利?br>所需频宽Q?3Kbps<br>Ҏ:是一般的GSM手机的通信~码方式,可以获得辑ֈ4.1左右Qos的语音通信质量(国际电联规定语音通信质量Qos满分?)<br>优点Q语韌量得C提高<br>~点Q系l容量降?br>应用领域QGSM<br>版税方式Q按个收?br>备注QFR全速率Q是一UGSM语音~码方式?br>                                                                               <br><br><span style="COLOR: red">EFR<br></span>cdQAudio<br>制定者:飞利?br>所需频宽Q?3Kbps<br>Ҏ:用于GSM手机Z全速率13Kbps的语音编码和发?可以获得更好更清晰的语音质量(接近Qos4.7),需要网l服务商开通此网l功能,手机才能配合实现?br>优点Q音质好<br>~点Q需要网l服务商开通此网l功能,且系l容量降?br>应用领域QGSM<br>版税方式Q按个收?br>备注QEFR增强型全速率,一UGSM|络语音的编码方式?/div> <dt>  <dd> <div><br><span style="COLOR: red">GSM-AMR(Adaptive Multi-Rate)<br></span>cdQAudio<br>制定者:飞利?br>所需频宽Q?Kbps(4.75 Kbps~12.2 Kbps)<br>Ҏ: 可以对语韌行替换和消音Q^滑噪韻I支持间断式传输,对语韌行动态侦查。能在各U网l条件下提供优质的语x果?br>优点Q音质出?br>~点Q?br>应用领域QGSM<br>版税方式Q按个收?br>备注QGSM-ASM是一U广泛用在GPRS和W-CDMA|络上的音频标准。在规范ETSI GSM06.90中对GSM-AMRq行了定义。AMR语音~码是GSM 2+和WCDMA的默认编码标准,是第三代无线通讯pȝ的语音编码标准。GSM-AMR标准ZACELPQ代数激q性预)~码。它能在q泛的传输条件下提供高品质的语音效果?br>                                                                                                  <br><br><span style="COLOR: red">EVRC(Enhanced Variable Rate CoderQ增强型可变速率~码?<br></span>cdQAudio<br>制定者:国Qualcomm通信公司(即高?<br>所需频宽Q?Kbps?3Kbps<br>Ҏ:支持三种码率Q?.6 Kbps, 4.8 Kbps ?1.2 KbpsQ,噪声抑制Q邮件过滤。能在各U网l条件下提供优质的语x果?br>优点Q音质出?br>~点Q?br>应用领域QCDMA<br>版税方式Q按个收?br>备注QEVRC~码q泛使用于CDMA|络。EVRC标准遵@规范TIA IS-127的内宏VEVRC~码ZRCELPQ松弛码Ȁq性预)标准。该~码可以以Rate 1Q?71bits/packetQ,Rate 1/2Q?0bits/packetQ或是Rate 1/8Q?6bits/packetQ的定wq行操作。在要求下,它也能生空包(0bits/packetQ?/div> <dt>  <dd> <div><br><span style="COLOR: red">QCELP(QualComm Code Excited Linear PredictiveQ受ȀU性预编?<br></span>cdQAudio<br>制定者:国Qualcomm通信公司(即高?<br>所需频宽Q?k的语音编码算?可工作于4/4.8/8/9.6Kbps{固定速率上,而且可变速率地工作于800Kbps?600Kbps之间)<br>Ҏ:使用适当的门限值来军_所需速率。QCELP是一U?k的语音编码算?可以?k的速率下提供接q?3k的话韛_~质?。这是一U可变速率话音~码Q根据h的说话特性(大家应该能够体会我们日常的沟通和交流时ƈ不是一直保持某U恒定的方式讲话Q有间断、有不同的声音频率等都是人的自然表达Q而采取的一U优化技术?br>优点Q话x晰、背景噪声小Q系l容量大<br>~点Q?不是Free<br>应用领域QCDMA<br>版税方式Q每q支付一W用权费用<br>备注QQCELPQ即QualComm Code Excited Linear PredictiveQQualComm受激U性预编码)。美国Qualcomm通信公司的专利语音编码算法,是北第二代数字Ud电话QCDMAQ的语音~码标准QIS95Q。这U算法不仅可工作?/4.8/8/9.6kbitQs{固定速率上,而且可变速率地工作于800bitQs?600bitQs之间。QCELP法被认为是到目前ؓ止效率效率最高的一U算法,它的主要特点之一Q是使用适当的门限值来军_所需速率。I‘1限值懈景噪声电q_化而变化,q样抑制了背景噪声Q得即使在喧闹的环境中Q也能得到良好的话音质量Q?CDMA8Kbit/s的话韌似GSM 13Mbit/s的话韟뀂CDMA采用QCELP~码{一pd技术,h话音清晰、背景噪声小{优势,其性能明显 优于其他无线Ud通信pȝQ语韌量可以与有线电话媲美?无线辐射低?/div> </dd> <img src ="http://www.shnenglu.com/gtwdaizi/aggbug/41884.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/gtwdaizi/" target="_blank">郭天?/a> 2008-01-25 13:29 <a href="http://www.shnenglu.com/gtwdaizi/articles/41884.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++字符串完全指引之一 —?Win32 字符~码http://www.shnenglu.com/gtwdaizi/articles/39809.html郭天?/dc:creator>郭天?/author>Fri, 28 Dec 2007 01:54:00 GMThttp://www.shnenglu.com/gtwdaizi/articles/39809.htmlhttp://www.shnenglu.com/gtwdaizi/comments/39809.htmlhttp://www.shnenglu.com/gtwdaizi/articles/39809.html#Feedback0http://www.shnenglu.com/gtwdaizi/comments/commentRss/39809.htmlhttp://www.shnenglu.com/gtwdaizi/services/trackbacks/39809.html

    C++字符串完全指引之一 —?Win32 字符~码


    原著QMichael Dunn

    译Q?a href="mailto:cjsun@insun.hit.edu.cn">Chengjie Sun



    原文出处Q?font color=#0000ff size=2>CodeProjectQThe Complete Guide to C++ Strings, Part I

    引言

      毫无疑问Q我们都看到q像 TCHAR, std::string, BSTR {各U各L字符串类型,q有那些?_tcs 开头的奇怪的宏。你也许正在盯着昄器发愁。本指引ȝ引进各种字符cd的目的,展示一些简单的用法Qƈ告诉您在必要Ӟ如何实现各种字符串类型之间的转换?br>  在第一部分Q我们将介绍3U字W编码类型。了解各U编码模式的工作方式是很重要的事情。即使你已经知道一个字W串是一个字W数l,你也应该阅读本部分。一旦你了解了这些,你将对各U字W串cd之间的关pL一个清楚地了解?br>  在第二部分,我们单独讲qstringc,怎样使用它及实现他们怺之间的{换?br>
    字符基础 -- ASCII, DBCS, Unicode

      所有的 string c都是以C-style字符串ؓ基础的。C-style 字符串是字符数组。所以我们先介绍字符cd。这里有3U编码模式对?U字W类型。第一U编码类型是单子节字W集Qsingle-byte character set or SBCSQ。在q种~码模式下,所有的字符都只用一个字节表C。ASCII是SBCS。一个字节表C的0用来标志SBCS字符串的l束?br>  W二U编码模式是多字节字W集Qmulti-byte character set or MBCSQ。一个MBCS~码包含一些一个字节长的字W,而另一些字W大于一个字节的长度。用在Windows里的MBCS包含两种字符cdQ单字节字符Qsingle-byte charactersQ和双字节字W(double-byte charactersQ。由于Windows里用的多字节字W绝大部分是两个字节长,所以MBCS常被用DBCS代替?br>  在DBCS~码模式中,一些特定的D保留用来表明他们是双字节字符的一部分。例如,在Shift-JIS~码中(一个常用的日文~码模式Q,0x81-0x9f之间?0xe0-oxfc之间的DC?q是一个双字节字符Q下一个子节是q个字符的一部分?q样的DUC"leading bytes",他们都大?x7f。跟随在一个leading byte子节后面的字节被UC"trail byte"。在DBCS中,trail byte可以是Q意非0倹{像SBCS一PDBCS字符串的l束标志也是一个单字节表示??br>  W三U编码模式是Unicode。Unicode是一U所有的字符都用两个字节编码的~码模式。Unicode字符有时也被UC宽字W,因ؓ它比单子节字W宽Q用了更多的存储空_。注意,Unicode不能被看作MBCS。MBCS的独特之处在于它的字W用不同长度的字节~码。Unicode字符串用两个字节表C的0作ؓ它的l束标志?br>  单字节字W包含拉丁文字母表,accented characters及ASCII标准和DOS操作pȝ定义的图形字W。双字节字符被用来表CZ亚及中东的语a。Unicode被用在COM及Windows NT操作pȝ内部?br>  你一定已l很熟悉单字节字W。当你用charӞ你处理的是单字节字符。双字节字符也用charcd来进行操作(q是我们会看到的关于双子节字符的很多奇怪的地方之一Q。Unicode字符用wchar_t来表C。Unicode字符和字W串帔R用前~L来表C。例如:

    wchar_t wch = L''1''; // 2 bytes, 0x0031
                wchar_t* wsz = L"Hello"; // 12 bytes, 6 wide characters

    字符在内存中是怎样存储?/strong>

      单字节字W串Q每个字W占一个字节按序依次存储Q最后以单字节表C的0l束。例如?Bob"的存贮Ş式如下:

    42 6F 62 00
    B o b BOS

    Unicode的存储Ş式,L"Bob"

    42 00 6F 00 62 00 00 00
    B o b BOS

    使用两个字节表示?来做l束标志?br>
      一眼看上去QDBCS 字符串很?SBCS 字符Ԍ但是我们一会儿看?DBCS 字符串的微妙之处Q它使得使用字符串操作函数和永字W指针遍历一个字W串时会产生预料之外的结果。字W串" " ("nihongo")在内存中的存储Ş式如下(LB和TB分别用来表示 leading byte ?trail byteQ?/p>
    93 FA 96 7B 8C EA 00
    LB TB LB TB LB TB EOS
    EOS

    值得注意的是Q?ni"的g能被解释成WORD型?xfa93Q而应该看作两个?3和fa以这U顺序被作ؓ"ni"的编码?br>
    使用字符串处理函?/strong>

      我们都已l见qC语言中的字符串函敎ͼstrcpy(), sprintf(), atoll(){。这些字W串只应该用来处理单字节字符字符丌Ӏ标准库也提供了仅适用于Unicodecd字符串的函数Q比如wcscpy(), swprintf(), wtol(){?br>  微Yq在它的CRT(C runtime library)中增加了操作DBCS字符串的版本。Str***()函数都有对应名字的DBCS版本_mbs***()。如果你料到可能会遇到DBCS字符Ԍ如果你的软g会被安装在用DBCS~码的国Ӟ如中国,日本{,你就可能会)Q你应该使用_mbs***()函数Q因Z们也可以处理SBCS字符丌Ӏ(一个DBCS字符串也可能含有单字节字W,q就是ؓ什么_mbs***()函数也能处理SBCS字符串的原因Q?br>  让我们来看一个典型的字符串来阐明Z么需要不同版本的字符串处理函数。我们还是用前面的Unicode字符?L"Bob"Q?/p>
    42 00 6F 00 62 00 00 00
    B o b BOS

      因ؓx86CPU是little-endianQ?x0042在内存中的存储Ş式是42 00。你能看出如果这个字W串被传lstrlen()函数会出C么问题吗Q它先看到W一个字?2Q然后是00Q?0是字W串l束的标志,于是strlen()会q回1。如果把"Bob"传给wcslen()Q将会得出更坏的l果。wcslen()会先看?x6f42Q然后是0x0062Q然后一直读C的缓冲区的末,直到发现00 00l束标志或者引起了GPF?br>  到目前ؓ止,我们已经讨论了str***()和wcs***()的用法及它们之间的区别。Str***()和_mbs**()之间的有区别区别呢?明白他们之间的区别,对于采用正确的方法来遍历DBCS字符串是很重要的。下面,我们先介绍字符串的遍历Q然后回到str***()与_mbs***()之间的区别这个问题上来?br>
    正确的遍历和索引字符?/strong>

      因ؓ我们中大多数人都是用着SBCS字符串成长的Q所以我们在遍历字符串时Q常怋用指针的++-?操作。我们也使用数组下标的表CŞ式来操作字符串中的字W。这两种方式是用于SBCS和Unicode字符Ԍ因ؓ它们中的字符有着相同的宽度,~译器能正确的返回我们需要的字符?br>  然而,当碰到DBCS字符串时Q我们必L弃这些习惯。这里有使用指针遍历DBCS字符串时的两条规则。违背了q两条规则,你的E序׃存在DBCS有关的bugs?/p>

  9. 1Q在前向遍历Ӟ不要使用++操作Q除非你每次都检查lead byteQ?
  10. 2Q永q不要?操作q行后向遍历?
  11.   我们先来阐述规则2Q因为找C个违背它的真实的实例代码是很Ҏ的。假设你有一个程序在你自q目录里保存了一个设|文Ӟ你把安装目录保存在注册表中。在q行Ӟ你从注册表中d安装目录Q然后合成配|文件名Q接着d该文件。假设,你的安装目录是C:\Program Files\MyCoolAppQ那么你合成的文件名应该是C:\Program Files\MyCoolApp\config.bin。当你进行测试时Q你发现E序q行正常?br>  现在Q想象你合成文g名的代码可能是这LQ?/p>

    bool GetConfigFileName ( char* pszName, size_t nBuffSize )
                {
                char szConfigFilename[MAX_PATH];
                // Read install dir from registry... we''ll assume it succeeds.
                // Add on a backslash if it wasn''t present in the registry value.
                // First, get a pointer to the terminating zero.
                char* pLastChar = strchr ( szConfigFilename, ''\0'' );
                // Now move it back one character.
                pLastChar--;
                if ( *pLastChar != ''\\'' )
                strcat ( szConfigFilename, "\\" );
                // Add on the name of the config file.
                strcat ( szConfigFilename, "config.bin" );
                // If the caller''s buffer is big enough, return the filename.
                if ( strlen ( szConfigFilename ) >= nBuffSize )
                return false;
                else
                {
                strcpy ( pszName, szConfigFilename );
                return true;
                }
                }      
      q是一D很健壮的代码,然而在遇到 DBCS 字符时它会出错。让我们来看看ؓ什么。假设一个日本用户用了你的E序Q把它安装在 C:\。下面是q个名字在内存中的存储Ş式:
     
    43 3A 5C 83 88 83 45 83 52 83 5C 00
          LB TB LB TB LB TB LB TB  
    C : \ EOS

      当?GetConfigFileName() 查尾部的''\\''Ӟ它寻扑֮装目录名中最后的?字节Q看它是{于''\\''的,所以没有重新增加一?'\\''。结果是代码q回了错误的文g名?br>  哪里出错了呢Q看看上面两个被用蓝色高量显C的字节。斜?'\\''的值是0x5c?' ''的值是83 5c。上面的代码错误的读取了一?trail byteQ把它当作了一个字W?br>  正确的后向遍历方法是使用能够识别DBCS字符的函敎ͼ使指针移动正的字节数。下面是正确的代码。(指针Ud的地方用U色标明Q?

    bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize )
                {
                char szConfigFilename[MAX_PATH];
                // Read install dir from registry... we''ll assume it succeeds.
                // Add on a backslash if it wasn''t present in the registry value.
                // First, get a pointer to the terminating zero.
                char* pLastChar = _mbschr ( szConfigFilename, ''\0'' );
                // Now move it back one double-byte character.
                  pLastChar = CharPrev ( szConfigFilename, pLastChar );
                if ( *pLastChar != ''\\'' )
                _mbscat ( szConfigFilename, "\\" );
                // Add on the name of the config file.
                _mbscat ( szConfigFilename, "config.bin" );
                // If the caller''s buffer is big enough, return the filename.
                if ( _mbslen ( szInstallDir ) >= nBuffSize )
                return false;
                else
                {
                _mbscpy ( pszName, szConfigFilename );
                return true;
                }
                }
                
      上面的函C用CharPrev() API使pLastChar向后Ud一个字W,q个字符可能是两个字节长。在q个版本里,if条g正常工作Q因为lead byte永远不会{于0x5c?br>  让我们来惌一个违背规?的场合。例如,你可能要一个用戯入的文g名是否多ơ出C'':''。如果,你?+操作来遍历字W串Q而不是用CharNext()Q你可能会发Z正确的错误警告如果恰巧有一个trail byte它的值的{于'':''的倹{?br>与规?相关的关于字W串索引的规则:
    2a. 永远不要使用减法dC个字W串的烦引?/pre>
                

    q背q条规则的代码和q背规则2的代码很怼。例如,

    char* pLastChar = &szConfigFilename [strlen(szConfigFilename) - 1];

    q和向后Ud一个指针是同样的效果?br>
    回到关于str***()和_mbs***()的区?/strong>

      现在Q我们应该很清楚Z么_mbs***()函数是必需的。Str***()函数Ҏ不考虑DBCS字符Q而_mbs***()考虑。如果,你调用strrchr("C:\\ ", ''\\'')Q返回结果可能是错误的,然而_mbsrchr()会认出最后的双字节字W,q回一个指向真?'\\''的指针?br>  关于字符串函数的最后一点:str***()和_mbs***()函数认ؓ字符串的长度都是以char来计的。所以,如果一个字W串包含3个双字节字符Q_mbslen()会q回6。Unicode函数q回的长度是按wchar_t来计的。例如,wcslen(L"Bob")q回3?br>
    Win32 API中的MBCS和Unicode

    两组 APIsQ?
      管你也总来没有注意过QWin32中的每个与字W串相关的API和message都有两个版本。一个版本接受MBCS字符Ԍ另一个接受Unicode字符丌Ӏ例如,Ҏ没有SetWindowText()q个APIQ相反,有SetWindowTextA()和SetWindowTextW()。后~A表明q是MBCS函数Q后~W表示q是Unicode版本的函数?br>  当你 build 一?Windows E序Q你可以选择是用 MBCS 或?Unicode APIs。如果,你曾l用qVC向导q且没有改过预处理的讄Q那表明你用的是MBCS版本。那么,既然没有 SetWindowText() APIQ我们ؓ什么可以用它呢?winuser.h头文件包含了一些宏Q例如:

    BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString );
                BOOL WINAPI SetWindowTextW ( HWND hWnd, LPCWSTR lpString );
                #ifdef UNICODE
                #define SetWindowText  SetWindowTextW
                #else
                #define SetWindowText  SetWindowTextA
                #endif      
    当用MBCS APIs来buildE序ӞUNICODE没有被定义,所以预处理器看刎ͼ
    #define SetWindowText SetWindowTextA

      q个宏定义把所有对SetWindowText的调用都转换成真正的API函数SetWindowTextA。(当然Q你可以直接调用SetWindowTextA() 或?SetWindowTextW()Q虽然你不必那么做。)
      所以,如果你想把默认用的API函数变成Unicode版的Q你可以在预处理器设|中Q把_MBCS从预定义的宏列表中删除,然后dUNICODE和_UNICODE?你需要两个都定义Q因Z同的头文件可能用不同的宏? 然而,如果你用char来定义你的字W串Q你会陷入一个尴的境地。考虑下面的代码:

    HWND hwnd = GetSomeWindowHandle();
                char szNewText[] = "we love Bob!";
                SetWindowText ( hwnd, szNewText );

    在预处理器把SetWindowText用SetWindowTextW来替换后Q代码变成:

    HWND hwnd = GetSomeWindowHandle();
                char szNewText[] = "we love Bob!";
                SetWindowTextW ( hwnd, szNewText );

      看到问题了吗Q我们把单字节字W串传给了一个以Unicode字符串做参数的函数。解册个问题的W一个方案是使用 #ifdef 来包含字W串变量的定义:

    HWND hwnd = GetSomeWindowHandle();
                #ifdef UNICODE
                wchar_t szNewText[] = L"we love Bob!";
                #else
                char szNewText[] = "we love Bob!";
                #endif
                SetWindowText ( hwnd, szNewText );

    你可能已l感受到了这样做会使你多么的头疹{完的解决Ҏ是用TCHAR.

    使用TCHAR

      TCHAR是一U字W串cdQ它让你在以MBCS和UNNICODE来buildE序时可以用同L代码Q不需要用繁琐的宏定义来包含你的代码。TCHAR的定义如下:

    #ifdef UNICODE
                typedef wchar_t TCHAR;
                #else
                typedef char TCHAR;
                #endif

    所以用MBCS来buildӞTCHAR是charQ用UNICODEӞTCHAR是wchar_t。还有一个宏来处理定义Unicode字符串常量时所需的L前缀?/p>

    #ifdef UNICODE
                #define _T(x) L##x
                #else
                #define _T(x) x
                #endif

      ##是一个预处理操作W,它可以把两个参数q在一赗如果你的代码中需要字W串帔RQ在它前面加上_T宏。如果你使用Unicode来buildQ它会在字符串常量前加上L前缀?/p>

    TCHAR szNewText[] = _T("we love Bob!");

      像是用宏来隐藏SetWindowTextA/W的细节一Pq有很多可以供你使用的宏来实现str***()和_mbs***(){字W串函数。例如,你可以用_tcsrchr宏来替换strrchr()、_mbsrchr()和wcsrchr()。_tcsrchrҎ你预定义的宏是_MBCSq是UNICODE来扩展成正确的函敎ͼ像SetWindowText所作的一栗?br>  不仅str***()函数有TCHAR宏。其他的函数如, _stprintfQ代替sprinft()和swprintf()Q?_tfopenQ代替fopen()和_wfopen()Q?MSDN?Generic-Text Routine Mappings."标题下有完整的宏列表?br>
    字符串和TCHAR typedefs

      ׃Win32 API文档的函数列表用函数的常用名字Q例如,"SetWindowText"Q,所有的字符串都是用TCHAR来定义的。(除了XP中引入的只适用于Unicode的APIQ。下面列Z些常用的typedefsQ你可以在msdn中看C们?/p>
    type Meaning in MBCS builds Meaning in Unicode builds
    WCHAR wchar_t wchar_t
    LPSTR zero-terminated string of char (char*) zero-terminated string of char (char*)
    LPCSTR constant zero-terminated string of char (const char*) constant zero-terminated string of char (const char*)
    LPWSTR zero-terminated Unicode string (wchar_t*) zero-terminated Unicode string (wchar_t*)
    LPCWSTR constant zero-terminated Unicode string (const wchar_t*) constant zero-terminated Unicode string (const wchar_t*)
    TCHAR char wchar_t
    LPTSTR zero-terminated string of TCHAR (TCHAR*) zero-terminated string of TCHAR (TCHAR*)
    LPCTSTR constant zero-terminated string of TCHAR (const TCHAR*) constant zero-terminated string of TCHAR (const TCHAR*)

    何时使用 TCHAR ?Unicode

      到现在,你可能会问,我们Z么要使用Unicode。我已经用了很多q的char。下?U情况下Q用Unicode会使你受益Q?/p>

  12. 1Q你的程序只q行在Windows NTpȝ中?
  13. 2Q?你的E序需要处理超qMAX_PATH个字W长的文件名?
  14. 3Q?你的E序需要用XP中引入的只有Unicode版本的API.
  15.   Windows 9x 中大多数?API 没有实现 Unicode 版本。所以,如果你的E序要在windows 9x中运行,你必M用MBCS APIs。然而,׃NTpȝ内部都用UnicodeQ所以用Unicode APIs会加快你的E序的运行速度。每ơ,你传递一个字W串调用MBCS APIQ操作系l会把这个字W串转换成Unicode字符Ԍ然后调用对应的Unicode API。如果一个字W串被返回,操作pȝq要把它转变回去。尽这个{换过E被高度优化了,但它寚w度造成的损失是无法避免的?br>  只要你用Unicode APIQNTpȝ允许使用非常长的文g名(H破了MAX_PATH的限ӞMAX_PATH=260Q。用Unicode API的另一个优Ҏ你的E序会自动处理用戯入的各种语言。所以一个用户可以输入英文,中文或者日文,而你不需要额外编写代码去处理它们?br>  最后,随着windows 9x产品的E出,微Yg正在抛弃MBCS APIs。例如,包含两个字符串参数的SetWindowTheme() API只有Unicode版本的。用Unicode来build你的E序会化字W串的处理,你不必在MBCS和Unicdoe之间怺转换?br>  即你现在不使用Unicode来build你的E序Q你也应该用TCHAR及其相关的宏。这样做不仅可以的代码可以很好地处理DBCSQ而且如果来你想用Unicode来build你的E序Q你只需要改变一下预处理器中的设|就可以实现了?br>

     

     

     

    作者简?/strong>
      Michael DunnQ居住在阛_城市z杉矶。他是如此的喜欢q里的天气以致于想一生都住在q里。他?q时开始编E,那时用的电脑是Apple //e?995q_?UCLA 获得数学学士学位Q随后在Symantec 公司?QA 工程师,?Norton AntiVirus l工作。他自学?Windows ?MFC ~程?999-2000q_他设计ƈ实现?Norton AntiVirus 的新界面。 
      Michael 现在?NapsterQ一个提供在U订阅音乐服务的公司Q做开发工作,他还开发了UltraBarQ一个IE工具栏插Ӟ它可以ɾ|络搜烦更加ҎQ给?googlebar 以沉重打击;他还开发了 CodeProject SearchBarQ与人共同创Z Zabersoft 公司Q该公司在洛杉矶和丹麦的 Odense 都设有办事处?br>  他喜Ƣ玩游戏。爱玩的游戏?pinball, bike ridingQ偶还?PS, Dreamcasth ?MAME 游戏。他因忘了自己曾l学q的语言Q法语、汉语、日语而感到悲哀?/td>

    ]]>Windows Mobile中如何徏立GPRSq接以便Socket能正帔R信http://www.shnenglu.com/gtwdaizi/articles/39578.html郭天?/dc:creator>郭天?/author>Tue, 25 Dec 2007 06:51:00 GMThttp://www.shnenglu.com/gtwdaizi/articles/39578.htmlhttp://www.shnenglu.com/gtwdaizi/comments/39578.htmlhttp://www.shnenglu.com/gtwdaizi/articles/39578.html#Feedback0http://www.shnenglu.com/gtwdaizi/comments/commentRss/39578.htmlhttp://www.shnenglu.com/gtwdaizi/services/trackbacks/39578.html 

    【版   本?/span>

    1.0.0

    【操作系l?/span>

    Windows Mobile 5.0

    【作   者?/span>

    谢红?#183;chrys ·chrys@163.com ·http://www.howa.com.cn

    【开发日期?/span>

    2007-12-11 01:23:56

     

    最q编写一个医疗项目的E序Q需要用 Windows Mobile 来做通信处理Q需要将手机端的数据通过GPRS传送至公网上的一个服务器上。数据传输我采用的是socketQ用数据U?/span>+ActiveSync调试通过Q数据传输正常,在准备将软g提交l质部门的时候,用真正的GPRS来做通信试Ӟ问题出来了,q接始终建立不了Q但用手机的IE览器却能正常打开|页Q而且奇怪的是只要用IE览器成功访问过一ơ网,我的 socket p正常q行数据通信Q看来传说中?/span>GPRS常连接被我误解了?/span>

    手机开?/span>GPRS以后Q我们的socket E序q不能直接徏立网l连接,需要用q接理器来获取当前可用q接Qƈ自动选择一个最佳的q接途径Q然后启用这个连接,在连接启动成功以后再?/span>socket q行|络q接方可正常q行。大?/span>GPRS拨号和连接过E就是在q里自动q行的吧。源代码中封装了一个连接管理的cd试代码Q可以清楚地看到Windows Mobile ?/span>socket ~程之前到底需要做什么样的操作?/span>

     

    首先需要枚丑ֽ前可用的q接

    void CConnectManager::EnumNetIdentifier ( OUT CStringArray &StrAry )

    {

           CONNMGR_DESTINATION_INFO networkDestInfo = {0};

     

           // 得到|络列表

           for ( DWORD dwEnumIndex=0; ; dwEnumIndex++ )

           {

                  memset ( &networkDestInfo, 0, sizeof(CONNMGR_DESTINATION_INFO) );

                  if ( ConnMgrEnumDestinations ( dwEnumIndex, &networkDestInfo ) == E_FAIL )

                  {

                         break;

                  }

                  StrAry.Add ( networkDestInfo.szDescription );

           }

    }

     

    接下来找?#8220;Internet”q个q接Q可用远E?/span>URL映射的方式来完成Q这样可以让pȝ自动选取一个最好的q接?/span>

    int CConnectManager::MapURLAndGUID ( LPCTSTR lpszURL, OUT GUID &guidNetworkObject, OUT CString *pcsDesc/*=NULL*/ )

    {

           if ( !lpszURL || lstrlen(lpszURL) < 1 )

                  return FALSE;

     

           memset ( &guidNetworkObject, 0, sizeof(GUID) );

           int nIndex = 0;

           HRESULT hResult = ConnMgrMapURL ( lpszURL, &guidNetworkObject, (DWORD*)&nIndex );

           if ( FAILED(hResult) )

           {

                  nIndex = -1;

                  DWORD dwLastError = GetLastError ();

                  AfxMessageBox ( _T("Could not map a request to a network identifier") );

           }

           else

           {

                  if ( pcsDesc )

                  {

                         CONNMGR_DESTINATION_INFO DestInfo = {0};

                         if ( SUCCEEDED(ConnMgrEnumDestinations(nIndex, &DestInfo)) )

                         {

                                *pcsDesc = DestInfo.szDescription;

                         }

                  }

           }

     

           return nIndex;

    }

     

    以下代码是用来启用指定编Lq接

    BOOL CConnectManager::EstablishConnection ( DWORD dwIndex )

    {

           ReleaseConnection ();

     

           // 得到正确的连接信?/span>

           CONNMGR_DESTINATION_INFO DestInfo = {0};

           HRESULT hResult = ConnMgrEnumDestinations(dwIndex, &DestInfo);

           BOOL bRet = FALSE;

           if(SUCCEEDED(hResult))

           {

                  // 初始化连接结?/span>

                  CONNMGR_CONNECTIONINFO ConnInfo;

     

                  ZeroMemory(&ConnInfo, sizeof(ConnInfo));

                  ConnInfo.cbSize = sizeof(ConnInfo);

                  ConnInfo.dwParams = CONNMGR_PARAM_GUIDDESTNET;

                  ConnInfo.dwFlags = CONNMGR_FLAG_PROXY_HTTP | CONNMGR_FLAG_PROXY_WAP | CONNMGR_FLAG_PROXY_SOCKS4 | CONNMGR_FLAG_PROXY_SOCKS5;

                  ConnInfo.dwPriority = CONNMGR_PRIORITY_USERINTERACTIVE;

                  ConnInfo.guidDestNet = DestInfo.guid;

                  ConnInfo.bExclusive     = FALSE;

                  ConnInfo.bDisabled = FALSE;

     

                  DWORD dwStatus = 0;

                  hResult = ConnMgrEstablishConnectionSync(&ConnInfo, &m_hConnection, 10*1000, &dwStatus );

                  if(FAILED(hResult))

                  {

                         m_hConnection = NULL;

                  }

                  else bRet = TRUE;

           }

     

           return bRet;

    }

     

    Z保q接是否真正可用Q需要检连接状态,在规定的旉内如果未取得“q接成功”的状态,则认接未能正常启用,可能需要配|手机的q接理器界?/font>

    BOOL CConnectManager::WaitForConnected ( int nTimeoutSec, DWORD *pdwStatus/*=NULL*/ )

    {

           DWORD dwStartTime = GetTickCount ();

           BOOL bRet = FALSE;

           while ( GetTickCount ()-dwStartTime < (DWORD)nTimeoutSec * 1000 )

           {

                  if ( m_hConnection )

                  {

                         DWORD dwStatus = 0;

                         HRESULT hr = ConnMgrConnectionStatus ( m_hConnection, &dwStatus );

                         if ( pdwStatus ) *pdwStatus = dwStatus;

                         if ( SUCCEEDED(hr) )

                         {

                                if ( dwStatus == CONNMGR_STATUS_CONNECTED )

                                {

                                       bRet = TRUE;

                                       break;

                                }

                         }

                  }

                  Sleep ( 100 );

           }

     

           return bRet;

    }

     

    xQ我们的q接启用工作已经做完了,我们可以用我们熟悉的 socket 来编写网l通信E序了。下面是一个测?/span> socket 试|络q接是否能正常徏立的例子Q?/span>

    SetWaitCursor ();

    CSocket sock;

    sock.Create ();

    if ( sock.Connect ( _T("www.baidu.com"), 80 ) )

    {

           RestoreCursor ();

           AfxMessageBox ( _T("Connect to www.baidu.com successfully"), MB_ICONINFORMATION );

    }

    else

    {

           RestoreCursor ();

           AfxMessageBox ( _T("Connect to www.baidu.com failed") );

    }

     

    GPRSDemo.exe 的?/span>

    E序启动以后出现如下界面Q?/font>

     

    q接可用?/span> 连接管理器是否可用

    映射URL – 是让pȝ自动L一个最好的q接

    枚D|络标识W?/span> 当前系l中所有可用的q接都会被枚丑և?/span>

    q接|络 枚丑և来的q接选中的那个连接进行连接启用操作?/span>

    q接状?/span> 表示可以获取到当前连接的状态;

    q接到公|测?/span> 利用 www.baidu.com 来测试连接是否已l正常启动?/span>

     

    操作步骤Q?/font>

    可以直接?#8220;枚D|络标识W?#8221;Q程序将所有当前在用的|络枚D出来q添加到 ListBox 控g中;

    q接|络。选择一个连接(例如Q?/span>InternetQ,?#8220;q接|络”按钮Q当提示 Connection net successfully 表示q接已经正常启用了?/span>

    ?#8220;q接到公|测?#8221;按钮QY件自动和 www.baidu.com q行q接试?/span>

     

    源代码下载地址Qhttp://www.pudn.com/downloads94/sourcecode/embed/detail373151.html



    ]]>
    WaitForMultipleObjects用法探烦http://www.shnenglu.com/gtwdaizi/articles/39556.html郭天?/dc:creator>郭天?/author>Tue, 25 Dec 2007 03:09:00 GMThttp://www.shnenglu.com/gtwdaizi/articles/39556.htmlhttp://www.shnenglu.com/gtwdaizi/comments/39556.htmlhttp://www.shnenglu.com/gtwdaizi/articles/39556.html#Feedback0http://www.shnenglu.com/gtwdaizi/comments/commentRss/39556.htmlhttp://www.shnenglu.com/gtwdaizi/services/trackbacks/39556.htmlWaitForMultipleObjects?/span>Windows中的一个功能非常强大的函数Q几乎可以等?/span>Windows中的所有的内核对象Q关于该函数的描q和例子?/span>MSDNQ)。但同时该函数在用法上却需要一定的技巧?/span>

    原型Q?/span>DWORD WaitForMultipleObjects(
     DWORD nCount,
     const HANDLE* lpHandles,
     BOOL bWaitAll,
     DWORD dwMilliseconds
    );

     

    ?/span>WaitForMultipleObjects{到多个内核对象的时候,如果它的bWaitAll 参数讄?/span>false。其q回值减?/span>WAIT_OBJECT_0 是参数lpHandles数组的序受如果同时有多个内核对象被出发,q个函数q回的只是其中序h的那个?/font>

    问题在q里Q我们如何可以获取所有被同时触发的内核对象。D个例子:我们需要在一个线E中处理从完成端口、数据库、和可等待定时器来的数据。一个典型的实现Ҏ是Q用WaitForMultipleObjects{待所有的q些事g。如果完成端口,数据库发q来的数据量非常大,可等待定时器旉也只有几十毫U。那么这些事件同时触发的几率可以说非常大Q我们不希望丢弃M一个被触发的事件。那么如何能高效地实现这一处理呢?

    MSDN中有一句非帔R要的描述Q它可以说是WaitForMultipleObjects用法的精髓:The function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one. When bWaitAll is FALSE, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait; the states of the objects not selected are unaffected.

    多个内核对象被触发时Q?/span>WaitForMultipleObjects选择其中序号最的q回。?/span>WaitForMultipleObjects它只会改变它返回的那个内核对象的状态?/span>

    q儿又会产生一个问题,如果序号最的那个对象频繁被触发,那么序号比它大的内核对象得不到被处理的Z?/font>

    Z解决q一问题Q可以采用双WaitForMultipleObjects机制来实现。见下面的例子:

    DWORD WINAPI ThreadProc(LPVOID lpParameter)

    {

        DWORD dwRet = 0;

        int   nIndex = 0;

        while(1)

        {

            dwRet = WaitForMultipleObjects(nCount,pHandles,false,INFINITE);

     

            switch(dwRet)

            {

            case WAIT_TIMEOUT:

                break;

            case WAIT_FAILED:

                return 1;

            default:

                {

                    nIndex = dwRet - WAIT_OBJECT_0;

     

                    ProcessHanlde(nIndex++);

                    //同时其他的事g

                    while(nIndex < nCount)

                    {

                        dwRet = WaitForMultipleObjects(nCount - nIndex,&pHandles[nIndex],false,0);

     

                        switch(dwRet)

                        {

                        case WAIT_TIMEOUT:

                            nIndex = nCount; //退出检?span>,因ؓ没有被触发的对象?span>.

                            break;

                        case WAIT_FAILED:

                            return 1;

                        default:

                            {

                                nIndex = dwRet - WAIT_OBJECT_0;

                                ProcessHanlde(nIndex++);

                            }

                            break

                        }

                    }

                }

                break;

            }

        }

        return 0;

    }



    ]]>
    Using WinInet HTTP functions in Full Asynchronous Modehttp://www.shnenglu.com/gtwdaizi/articles/39107.html郭天?/dc:creator>郭天?/author>Thu, 20 Dec 2007 05:49:00 GMThttp://www.shnenglu.com/gtwdaizi/articles/39107.htmlhttp://www.shnenglu.com/gtwdaizi/comments/39107.htmlhttp://www.shnenglu.com/gtwdaizi/articles/39107.html#Feedback0http://www.shnenglu.com/gtwdaizi/comments/commentRss/39107.htmlhttp://www.shnenglu.com/gtwdaizi/services/trackbacks/39107.htmlIntroduction

    If you have ever dug into the MSDN for WinInet API, you noticed that it can be used asynchronously and that it is the recommended way to use it.

    If then you decide to use it, you won’t find any explanation of how to use it asynchronously. And no samples are available anywhere on Internet. After a long research and lots of testing, I finally managed to reconstruct a big part of the (voluntary?) missing documentation.

    Why asynchronous is better? Because it can handle timeouts correctly. Just what’s missing in WinInet under IE5.5.

    If you try to use TerminateThread or CloseHandle functions to handle timeouts (these methods are given in MSDN articles), you’ll fall into unrecoverable leaks of all kinds.

    This has been tested successfully with: IE4.01SP3, IE5.0, IE5.01, IE5.5SP1 under WinNT4 on mono and multiprocessor machines, under a stressed environment (15 concurrent instances running non-stop for 12 hours on multi-proc NT server machines).

    Theory

    To use WinInet functions in full asynchronous mode, you must do things in the right order:

    1. Use INTERNET_FLAG_ASYNC to open the session
    2. Set a status callback using InternetSetStatusCallback
    3. Open the connection using InternetOpenUrl
    4. If InternetOpenUrl returned NULL and GetLastError is ERROR_IO_PENDING:
      • wait for the INTERNET_STATUS_HANDLE_CREATED notification in the callback, and save the connection Handle.
      • wait for the INTERNET_STATUS_REQUEST_COMPLETE notification in the callback before going further.
    5. Extract the content-length from the header and set up an INTERNET_BUFFERS structure:
      • dwStructSize = sizeof(INTERNET_BUFFERS)
      • lpvBuffer = your allocated buffer
      • dwBufferLength = its length
    6. Use InternetReadFileEx with the IRF_ASYNC flag to read the remaining data asynchronously. Don’t use InternetReadFile since it is a synchronous function.
    7. If InternetReadFileEx returned False and GetLastError is ERROR_IO_PENDING: wait for the INTERNET_STATUS_REQUEST_COMPLETE notification in the callback before going further.

      Warning: INTERNET_BUFFERS members are modified asynchronously (only the dwBufferLength member and the content of the buffer).

    8. If the dwBufferLength member is not 0, move the lpvBuffer pointer from this amount and subtract this amount from the buffer length so dwBufferLength reflects the remaining size lpvBuffer points to, then loop to 6.
    9. Close the connection handle with InternetCloseHandle and wait for INTERNET_STATUS_HANDLE_CLOSING and the facultative INTERNET_STATUS_REQUEST_COMPLETE notification (sent only if an error occurs – like a sudden closed connection -, you must test the cases).

    At this state, you can either begin a new connection process or close the session handle. But before closing it, you should un-register the callback function.

    Detail

    After the theory, let’s look at some code for some of the points:

    1&2: Create the connection using INTERNET_FLAG_ASYNC and setup the callback func:

    m_Session = InternetOpen(AGENT_NAME, INTERNET_OPEN_TYPE_PRECONFIG,
    NULL, NULL, INTERNET_FLAG_ASYNC);
    InternetSetStatusCallback( m_Session,
    (INTERNET_STATUS_CALLBACK)InternetCallbackFunc );

    3&4: Open the connection using InternetOpenUrl and wait for INTERNET_STATUS_REQUEST_COMPLETE

    Use the lParam to send a session identifier to your callback. I always use the this pointer of my class for it. I assume you know how to handle callbacks.

    InternetOpenUrl( m_Session, uurl, NULL, 0,
    INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE |
    INTERNET_FLAG_NO_CACHE_WRITE, (LPARAM)this );

    The callback will receive a lots of messages then. Here are their orders along with the dwInternetStatus value:

    [openUrl] InternetStatus: 60 INTERNET_STATUS_HANDLE_CREATED
    **At this point you can save the HINTERNET handle using code like this in your callback:
    INTERNET_ASYNC_RESULT* res = (INTERNET_ASYNC_RESULT*)lpvStatusInformation;
    m_hHttpFile = (HINTERNET)(res->dwResult);
    [openUrl] InternetStatus: 10
    [openUrl] InternetStatus: 11
    [openUrl] InternetStatus: 20
    [openUrl] InternetStatus: 21
    [openUrl] InternetStatus: 30
    [openUrl] InternetStatus: 31
    [openUrl] InternetStatus: 40
    [openUrl] InternetStatus: 41
    [openUrl] InternetStatus: 100 INTERNET_STATUS_REQUEST_COMPLETE

    5: Extract the content-length and set up the INTERNET_BUFFERS structure

    Once you have the handle, try to call HttpQueryInfo with HTTP_QUERY_CONTENT_LENGTH to get the size of the data to retrieve. This function can fail if the content-length field is not in the HTTP header.

    Set up the INTERNET_BUFFERS structure.

    INTERNET_BUFFERS ib = { sizeof(INTERNET_BUFFERS) };
    ib.lpvBuffer = your allocated buffer
    ib.dwBufferLength = its length

    The dwBufferTotal is provided for your own use and is never modified by WinInet (as far as I know). I use it to store the total size of the received data.

    6&7&8 Read the remaining data in a loop

    Use InternetReadFileEx with the IRF_ASYNC flag to read the remaining data asynchronously. Don’t use InternetReadFile since it is a synchronous function. You must loop on InternetReadFileEx while the ib.dwBufferLength is not 0. Before each iteration you must adjust the lpvBuffer pointer and reset the dwBufferLength members of ib: add the received length to the pointer and set dwBufferLength to your remaining buffer size.

    //Start the pump
    BOOL bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
    if(!bOk && GetLastError()==ERROR_IO_PENDING)
    wait...
    //Pump
    while( bOk && ib.dwBufferLength!=0 )
    {
    (adjust ib values)
    bOk = InternetReadFileEx( m_hHttpFile, &ib, IRF_ASYNC, (LPARAM)this );
    if(!bOk && GetLastError()==ERROR_IO_PENDING)
    wait...
    }

    Your callback should receive these notifications (maybe more than once):

    [connect] InternetStatus: 40 (receiving response)
    [connect] InternetStatus: 41 (response received)
    [connect] InternetStatus: 50
    [connect] InternetStatus: 51
    and maybe
    [connect] InternetStatus: 100 INTERNET_STATUS_REQUEST_COMPLETE

    The last is received only if GetLastError() returned ERROR_IO_PENDING. If you stored the total data size (in bytes) in the dwBufferTotal member, use it to set the final “0” in your string buffer (if it’s a string).

    buf[ib.dwBufferTotal] = 0;

    9 Close the connection handle

    InternetCloseHandle( m_httpFile );

    The callback will receive this notification when the handle is closed:

    [connect] InternetStatus: 70 INTERNET_STATUS_HANDLE_CLOSING

    In most error cases, the connection is closed unexpectedly. If it happens you’ll receive a 70 followed by a 100 (INTERNET_STATUS_REQUEST_COMPLETE). This can happen anywhere during the process.

    10 Before closing the m_Session handle

    You must deregister the callback:

    InternetSetStatusCallback( m_Session, NULL );

    This should help those who tried to go through asynchronous mode in WinInet! Sorry, there are no attached files but you should be able to use the functions and create nice classes now. If you liked this article please add an entry in my guestbook and buy me a license of my shareware.

    Bibliography

    About the Author

    Benjamin Mayrargue



    Location: United States United States

    Other popular Internet / Network articles:



    ]]>
    C++q回引用cd 指针的引?/title><link>http://www.shnenglu.com/gtwdaizi/articles/38521.html</link><dc:creator>郭天?/dc:creator><author>郭天?/author><pubDate>Fri, 14 Dec 2007 07:59:00 GMT</pubDate><guid>http://www.shnenglu.com/gtwdaizi/articles/38521.html</guid><wfw:comment>http://www.shnenglu.com/gtwdaizi/comments/38521.html</wfw:comment><comments>http://www.shnenglu.com/gtwdaizi/articles/38521.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/gtwdaizi/comments/commentRss/38521.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/gtwdaizi/services/trackbacks/38521.html</trackback:ping><description><![CDATA[<p><span style="COLOR: red"><strong>C++q回引用cd</strong></span><br>A& a(){ return *this;} q成了一个固定地址的指针,q把指针带给?<br><br>但A a() { return *this;}会生成一个时对象变量,q把q个临时变量l你 <br>q样多了一步操?<br><br>当返回一个变量时Q会产生拯。当q回一个引用时Q不会发生拷贝,你可以将引用看作是一个变量的别名Q就是其他的名字Q引用和被引用的变量其实是一个东西,只是有了两个名字而已?<br><br>问题的关键是Q当你想要返回一个引用而不是一个拷贝时Q你要确保这个引用的有效性,比如Q?<br>int & fun() { int a; a=10; return a; } <br>q样是不行的Q因为a会在fun退出时被销毁,q时q回的a的引用是无效的?<br>q种情况下,如果fun的返回类型不是int & 而是int没有问题了?</p> <br><span style="COLOR: red"><strong>指针的引?br></strong><font face="Courier New" color=#000000>GetNearestFontInTwips(CFont *&aFont, const TFontSpec &aFontSpec);<br><br>W一个参数aFont是一个指? 前面加上*&表示指针的引? 其实可以如下看待q个方式(CFont*) &aFont, q就一目了然了.</font></span> <img src ="http://www.shnenglu.com/gtwdaizi/aggbug/38521.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/gtwdaizi/" target="_blank">郭天?/a> 2007-12-14 15:59 <a href="http://www.shnenglu.com/gtwdaizi/articles/38521.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CListCtrl::SortItemsҎhttp://www.shnenglu.com/gtwdaizi/articles/32783.html郭天?/dc:creator>郭天?/author>Mon, 24 Sep 2007 06:48:00 GMThttp://www.shnenglu.com/gtwdaizi/articles/32783.htmlhttp://www.shnenglu.com/gtwdaizi/comments/32783.htmlhttp://www.shnenglu.com/gtwdaizi/articles/32783.html#Feedback1http://www.shnenglu.com/gtwdaizi/comments/commentRss/32783.htmlhttp://www.shnenglu.com/gtwdaizi/services/trackbacks/32783.html

    BOOL SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData );

    pfnCompare:指定的是一个回调函数的入口地址,q个函数在列表中的连l的节点要进行比较的时候调?比如说列表中有三个元?I1,I2,I3, 现在要对q个三个元素排序,那么I1 ?I2比较时会调用q个函数,I2 ?I3比较时也会调?当然,W二ơ的I2可能已经跟I1互换?. 该函数必d明ؓstaticcd,或者一个非cL员函?

    dwData: 指定的是列表对象.

    回调函数的原型如?
    MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
    参数lParam1和lParam2 其实是两个列表Item的烦引? 排序实际上就是对q个D行比?
    lParamSort包含了指向TreeCtrl控g的指?可强制{换过?

    q里需要注意的问题?在调用SortItems()Ҏ之前,必须调用SetItemData( int nItem, DWORD dwData ) Ҏ来设|回调函C使用到LPARAM lParam1, LPARAM lParam2
    MSDN中对于SetItemData()函数的解释如?
    This function sets the 32-bit application-specific value associated with the item specified by nItem. This value is the lParam member of the LVITEM structure, as described in the Platform SDK.

    所以不调用SetItemDataҎ,直接去调用SortItemҎ׃出现排序无效的结?

    //SortItems函数的回调函?br>int CALLBACK CConfigDlg::ListCtrlCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
    {
        INT iRet = 0;
        if (lParam1 > lParam2)
        {
            iRet = 1;
        }
        else
        {
            iRet = -1;
        }
        return iRet;
    }

    ]]>
    VC的Bug-安装q程中创建DCOM出错(Setup Was Unable to Create a DCOM User Account)http://www.shnenglu.com/gtwdaizi/articles/32682.html郭天?/dc:creator>郭天?/author>Sat, 22 Sep 2007 11:49:00 GMThttp://www.shnenglu.com/gtwdaizi/articles/32682.htmlhttp://www.shnenglu.com/gtwdaizi/comments/32682.htmlhttp://www.shnenglu.com/gtwdaizi/articles/32682.html#Feedback0http://www.shnenglu.com/gtwdaizi/comments/commentRss/32682.htmlhttp://www.shnenglu.com/gtwdaizi/services/trackbacks/32682.html今天在重新安装VC6.0企业版的时候出现这个问? 查了一下资?原文如下:

    VC6.Setup Was Unable to Create a DCOM User
    2006-10-29 03:08
    BUG: "Setup Was Unable to Create a DCOM User Account" Error Message in Visual Studio 6.0
    SYMPTOMS
    When you run the Visual Studio 6.0 Setup program, you may receive the following error message:
    Setup was unable to create a DCOM user account in order to register <path>\valec.exe
    This first error message may be followed by a second message that indicates that Setup failed.
     
    CAUSE
    Visual Studio Analyzer, which is one of the products that is included in Visual Studio Enterprise Edition version 6.0, cannot create the local user account that it needs to run because of changes to the security policies for users in Windows 2000.
     
    RESOLUTION
    Re-install Visual Studio 6.0 Enterprise Edition without Visual Studio Analyzer:
    1. Use the Custom setup, on the Visual Studio 6.0 Enterprise - Custom page, click Enterprise Tools, and then click Change Option.
    2. On the Visual Studio 6.0 Enterprise - Enterprise Tools page, under Options, make sure the Visual Studio Analyzer check box is not selected.
    3. Click to select all the other Visual Studio components that you want to install, and then click OK.
    4. Click Continue, and then follow the instructions that appear.
    To install Visual Studio Analyzer: 1. In Control Panel, double-click Add/Remove Programs, and then click Microsoft Visual Studio 6.0 Enterprise Edition.
    2. Click Change/Remove.
    3. In Visual Studio 6.0 Enterprise Setup, click Add/Remove.
    4. On the Visual Studio 6.0 Enterprise - Maintenance page, click Enterprise Tools, and then click Change Option.
    5. On the Visual Studio 6.0 Enterprise - Enterprise Tools page, under Options, click Visual Studio Analyzer, and then click OK.
    6. On the Visual Studio 6.0 Enterprise - Maintenance page, click Continue, and then follow the instructions that appear.

    When you receive the error message that is described in the "Symptoms" section, continue with the Visual Studio Setup Wizard. Setup reports a failure.
    To create a local account, which Visual Studio Analyzer will run as: 1. On the computer that is running Visual Studio Enterprise Edition 6.0, create a local user. For information about how to create a local user, see Windows 2000 Help. 
    2. Run Distributed COM Configuration (dcomcnfg.exe).
    3. On the Applications tab, click MSVSA Local Event Concentrator Class, and then click Properties.
    4. On the Identity tab, set This User to match the user and password you created in step 1 of this procedure.


    STATUS
    Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article. 



    ]]>
    ƷþavĻ| þֻоƷҳ| պһƵþ| ۺϾþúݺɫ99h| þۺϾɫۺϾ99| þ99ۺϾƷҳ| ޹˾þһҳ| Ʒþˬ| þþһƷ99þþƷ66| ˾þˬ| þùֱ| þþavҰһ| һþaþþƷۺ| Ʒþþһ| ݺɫۺϾþ| һۺϾþù| 2021þùԲľƷ| 2021Ʒҹþ| ݾƷŮ˾þþþþ | AVպAVþþ| þþƷվ| þƵ1| 99þۺϾƷ| ƷۺϾþþþþ97| Ʒþùһ㽶 | þþþþԻAV| Ļþ| þþþ޾Ʒ| þþƷ| پþþƷþ| 777þµַ| ݺɫþþһ| ɫվþav| þ99Ʒþþþþ| 97rþþƷ99| ɫþþۺľþav| þ޹Ʒ| þù˾Ʒ| þۺɫһ| þù޸ۿ| ξþ99ƷþþþþС˵|