欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
VC知識庫文章 - COM 組件設計與應用(三)——數據類(lèi)型

一、前言
  上回書(shū)介紹了GUID、CLSID、IID和接口的概念。本回的重點(diǎn)是介紹 COM 中的數據類(lèi)型。咋還不介紹組件程序的設計步驟呀?咳......別著(zhù)急,別著(zhù)急!孔子曰:“飯要一口一口地吃”;老子語(yǔ):“心急吃不了熱豆腐”,孫子云:“走一步看一步吧” ...... 先掌握必要的知識,將來(lái)寫(xiě)起程序來(lái)才會(huì )得心應手也:-)
  走入正題之前,請大家牢牢記住一條原則:COM 組件是運行在分布式環(huán)境中的。比如,你寫(xiě)了一個(gè)組件程序(DLL或EXE),那么使用者可能是在本機的某個(gè)進(jìn)程內加載組件(INPROC_SERVER);也可能是從另一個(gè)進(jìn)程中調用組件的進(jìn)程(LOCAL_SERVER);也可能是在這臺計算機上調用地球那邊計算機上的組件(REMOTE_SERVER)。所以在理解和設計的時(shí)候,要時(shí)時(shí)刻刻想起這句話(huà)???!拿出小本本,記下來(lái)!

二、HRESULT 函數返回值
  每個(gè)人在做程序設計的時(shí)候,都有他們各自的哲學(xué)思想。拿函數返回值來(lái)說(shuō),就有好多種形式。
 

函數返回值返回值信息
double sin(double)

浮點(diǎn)數值

計算正玄值
BOOL DeleteFile(LPCTSTR)

布爾值

文件刪除是否成功。如失敗,需要GetLastError()才能取得失敗原因
void * malloc(size_t)

內存指針

內存申請,如果失敗,返回空指針 NULL
LONG RegDeleteKey(HKEY,LPCTSTR)

整數

刪除注冊表項。0表示成功,非0失敗,同時(shí)這個(gè)值就反映了失敗的原因
UINT DragQueryFile(HDROP,UINT,LPTSTR,UINT)

整數

取得拖放文件信息。以不同的參數調用,則返回不同的含義:
一會(huì )兒表示文件個(gè)數,一會(huì )兒表示文件名長(cháng)度,一會(huì )兒表示字符長(cháng)度
......  ......

...

......  ......

  如此紛繁復雜的返回值,如此含義多變的返回值,使得大家在學(xué)習和使用的過(guò)程中,增加了額外的困難。好了,COM 的設計規范終于對他們進(jìn)行了統一。組件API及接口指針中,除了IUnknown::AddRef()和IUnknown::Release()兩個(gè)函數外,其它所有的函數,都以 HRESULT 作為返回值。大家想象一個(gè)組件的接口函數比如叫Add(),完成2個(gè)整數的加法運算,在C語(yǔ)言中,我們可以如下定義:

      long Add( long n1, long n2 )      {          return n1 + n2;      }
  還記得剛才我們說(shuō)的原則嗎?COM 組件是運行在分布式環(huán)境中的。也就是說(shuō),這個(gè)函數可能運行在“地球另一邊”的計算機上,既然運行在那么遙遠的地方,就有可能出現服務(wù)器關(guān)機、網(wǎng)絡(luò )掉線(xiàn)、運行超時(shí)、對方不在服務(wù)區......等異常。于是,這個(gè)加法函數,除了需要返回運算結果以外,還應該返回一個(gè)值------函數是否被正常執行了。
      HRESULT Add( long n1, long n2, long *pSum )      {          *pSum = n1 + n2;          return S_OK;      }
  如果函數正常執行,則返回 S_OK,同時(shí)真正的函數運行結果則通過(guò)參數指針?lè )祷?。如果遇到了異常情況,則COM系統經(jīng)過(guò)判斷,會(huì )返回相應的錯誤值。常見(jiàn)的返回值有:
 
HRESULT含義
S_OK0x00000000成功
S_FALSE0x00000001函數成功執行完成,但返回時(shí)出現錯誤
E_INVALIDARG0x80070057參數有錯誤
E_OUTOFMEMORY0x8007000E內存申請錯誤
E_UNEXPECTED0x8000FFFF未知的異常
E_NOTIMPL0x80004001未實(shí)現功能
E_FAIL0x80004005沒(méi)有詳細說(shuō)明的錯誤。一般需要取得 Rich Error 錯誤信息(注1)
E_POINTER0x80004003無(wú)效的指針
E_HANDLE0x80070006無(wú)效的句柄
E_ABORT0x80004004終止操作
E_ACCESSDENIED0x80070005訪(fǎng)問(wèn)被拒絕
E_NOINTERFACE0x80004002不支持接口


圖一、HRESULT 的結構

  HRESULT 其實(shí)是一個(gè)雙字節的值,其最高位(bit)如果是0表示成功,1表示錯誤。具體參見(jiàn) MSDN 之"Structure of COM Error Codes"說(shuō)明。我們在程序中如果需要判斷返回值,則可以使用比較運算符號;switch開(kāi)關(guān)語(yǔ)句;也可以使用VC提供的宏:

      HRESULT hr = 調用組件函數;      if( SUCCEEDED( hr ) ){...} // 如果成功      ......      if( FAILED( hr ) ){...} // 如果失敗      ......

三、UNICODE
  計算機發(fā)明后,為了在計算機中表示字符,人們制定了一種編碼,叫ASCII碼。ASCII碼由一個(gè)字節中的7位(bit)表示,范圍是0x00 - 0x7F 共128個(gè)字符。他們以為這128個(gè)數字就足夠表示abcd....ABCD....1234 這些字符了。
  咳......說(shuō)英語(yǔ)的人就是“笨”!后來(lái)他們突然發(fā)現,如果需要按照表格方式打印這些字符的時(shí)候,缺少了“制表符”。于是又擴展了ASCII的定義,使用一個(gè)字節的全部8位(bit)來(lái)表示字符了,這就叫擴展ASCII碼。范圍是0x00 - 0xFF 共256個(gè)字符。
  咳......說(shuō)中文的人就是聰明!中國人利用連續2個(gè)擴展ASCII碼的擴展區域(0xA0以后)來(lái)表示一個(gè)漢字,該方法的標準叫GB-2312。后來(lái),日文、韓文、阿拉伯文、臺灣繁體(BIG-5)......都使用類(lèi)似的方法擴展了本地字符集的定義,現在統一稱(chēng)為 MBCS 字符集(多字節字符集)。這個(gè)方法是有缺陷的,因為各個(gè)國家地區定義的字符集有交集,因此使用GB-2312的軟件,就不能在BIG-5的環(huán)境下運行(顯示亂碼),反之亦然。
  咳......說(shuō)英語(yǔ)的人終于變“聰明”一些了。為了把全世界人民所有的所有的文字符號都統一進(jìn)行編碼,于是制定了UNICODE標準字符集。UNICODE 使用2個(gè)字節表示一個(gè)字符(unsigned shor int、WCHAR、_wchar_t、OLECHAR)。這下終于好啦,全世界任何一個(gè)地區的軟件,可以不用修改地就能在另一個(gè)地區運行了。雖然我用 IE 瀏覽日本網(wǎng)站,顯示出我不認識的日文文字,但至少不會(huì )是亂碼了。UNICODE 的范圍是 0x0000 - 0xFFFF 共6萬(wàn)多個(gè)字符,其中光漢字就占用了4萬(wàn)多個(gè)。嘿嘿,中國人賺大發(fā)了:0)
  在程序中使用各種字符集的方法:

      const char * p = "Hello"; // 使用 ASCII 字符集      const char * p = "你好"; // 使用 MBCS 字符集,由于 MBCS 完全兼容 ASCII,多數情況下,我們并不嚴格區分他們      LPCSTR p = "Hello,你好"; // 意義同上            const WCHAR * p = L"Hello,你好"; // 使用 UNICODE 字符集      LPCOLESTR p = L"Hello,你好"; // 意義同上            // 如果預定義了_UNICODE,則表示使用UNICODE字符集;如果定義了_MBCS,則表示使用 MBCS      const TCHAR * p = _T("Hello,你好");       LPCTSTR p = _T("Hello,你好"); // 意義同上
  在上面的例子中,T是非常有意思的一個(gè)符號(TCHAR、LPCTSTR、LPTSTR、_T()、_TEXT()...),它表示使用一種中間類(lèi)型,既不明確表示使用 MBCS,也不明確表示使用 UNICODE。那到底使用哪種字符集那?嘿嘿......編譯的時(shí)候決定吧。設置條件編譯的方式是:VC6中,"Project\Settings...\C/C++卡片 Preprocessor definitions" 中添加或修改 _MBCS、_UNICODE;VC.NET中,"項目\屬性\配置屬性\常規\字符集"然后用組合窗進(jìn)行選擇。使用 T 類(lèi)型,是非常好的習慣,嚴重推薦!

四、BSTR
  COM 中除了使用一些簡(jiǎn)單標準的數據類(lèi)型外(注2),字符串類(lèi)型需要特別重點(diǎn)地說(shuō)明一下。還記得原則嗎?COM 組件是運行在分布式環(huán)境中的。通俗地說(shuō),你不能直接把一個(gè)內存指針直接作為參數傳遞給COM函數。你想想,系統需要把這塊內存的內容傳遞到“地球另一 邊”的計算機上,因此,我至少需要知道你這塊內存的尺寸吧?不然讓我如何傳遞呀?傳遞多少字節呀?!而字符串又是非常常用的一種類(lèi)型,因此 COM 設計者引入了 BASIC 中字符串類(lèi)型的表示方式---BSTR。BSTR 其實(shí)是一個(gè)指針類(lèi)型,它的內存結構是:(輸入程序片段 BSTR p = ::SysAllocString(L"Hello,你好");斷點(diǎn)執行,然后觀(guān)察p的內存)


圖二、BSTR 內存結構

  BSTR 是一個(gè)指向 UNICODE 字符串的指針,且 BSTR 向前的4個(gè)字節中,使用DWORD保存著(zhù)這個(gè)字符串的字節長(cháng)度( 沒(méi)有含字符串的結束符)。因此系統就能夠正確處理并傳送這個(gè)字符串到“地球另一 邊”了。特別需要注意的是,由于BSTR的指針就是指向 UNICODE 串,因此 BSTR 和 LPOLESTR 可以在一定程度上混用,但一定要注意:
  有函數 fun(LPCOLESTR lp),則你調用 BSTR p=...; fun(p); 正確
  有函數 fun(const BSTR bstr),則你調用 LPCOLESTR p=...; fun(p); 錯誤?。?!
有關(guān) BSTR 的處理函數:
 
API 函數說(shuō)明
SysAllocString()申請一個(gè) BSTR 指針,并初始化為一個(gè)字符串
SysFreeString()釋放 BSTR 內存
SysAllocStringLen()申請一個(gè)指定字符長(cháng)度的 BSTR 指針,并初始化為一個(gè)字符串
SysAllocStringByteLen()申請一個(gè)指定字節長(cháng)度的 BSTR 指針,并初始化為一個(gè)字符串
SysReAllocStringLen()重新申請 BSTR 指針

CString 函數

說(shuō)明

AllocSysString()從 CString 得到 BSTR
SetSysString()重新申請 BSTR 指針,并復制到 CString 中

CComBSTR 函數

ATL 的 BSTR 包裝類(lèi)。在 atlbase.h 中定義

Append()、AppendBSTR()、AppendBytes()、ArrayToBSTR()、BSTRToArray()、AssignBSTR()、Attach()、Detach()、Copy()、CopyTo()、Empty()、Length()、ByteLength()、ReadFromStream()、WriteToStream()、LoadString()、ToLower()、ToUpper()
運算符重載:!,!=,==,<,>,&,+=,+,=,BSTR
    太多了,但從函數名稱(chēng)不能看出其基本功能。詳細資料,查看MSDN 吧。另外,左側函數,有很多是 ATL 7.0 提供的,VC6.0 下所帶的 ATL 3.0 不支持。
    由于我們將來(lái)主要用 ATL 開(kāi)發(fā)組件程序,因此使用 ATL 的 CComBSTR 為主。VC也提供了其它的包裝類(lèi) _bstr_t。


五、各種字符串類(lèi)型之間的轉換
  1、函數 WideCharToMultiByte(),轉換 UNICODE 到 MBCS。使用范例:

      LPCOLESTR lpw = L"Hello,你好";      size_t wLen = wcslen( lpw ) + 1;  // 寬字符字符長(cháng)度,+1表示包含字符串結束符            int aLen=WideCharToMultiByte(  // 第一次調用,計算所需 MBCS 字符串字節長(cháng)度		CP_ACP,		0,		lpw,  // 寬字符串指針		wLen, // 字符長(cháng)度		NULL,		0,  // 參數0表示計算轉換后的字符空間		NULL,		NULL);	      LPSTR lpa = new char [aLen];	      WideCharToMultiByte(		CP_ACP,		0,		lpw,		wLen,		lpa,  // 轉換后的字符串指針		aLen, // 給出空間大小		NULL,		NULL);      // 此時(shí),lpa 中保存著(zhù)轉換后的 MBCS 字符串      ... ... ... ...      delete [] lpa;

    2、函數 MultiByteToWideChar(),轉換 MBCS 到 UNICODE。使用范例:
      LPCSTR lpa = "Hello,你好";      size_t aLen = strlen( lpa ) + 1;            int wLen = MultiByteToWideChar(		CP_ACP,		0,		lpa,		aLen,		NULL,		0);            LPOLESTR lpw = new WCHAR [wLen];      MultiByteToWideChar(		CP_ACP,		0,		lpa,		aLen,		lpw,		wLen);      ... ... ... ...      delete [] lpw;

    3、使用 ATL 提供的轉換宏。
 

A2BSTROLE2AT2AW2A
A2COLEOLE2BSTRT2BSTRW2BSTR
A2CTOLE2CAT2CAW2CA
A2CWOLE2CTT2COLEW2COLE
A2OLEOLE2CWT2CWW2CT
A2TOLE2TT2OLEW2OLE
A2WOLE2WT2WW2T

上表中的宏函數,其實(shí)非常容易記憶:
2好搞笑的縮寫(xiě),to 的發(fā)音和 2 一樣,所以借用來(lái)表示“轉換為、轉換到”的含義。
AANSI 字符串,也就是 MBCS。
W、OLE寬字符串,也就是 UNICODE。
T中間類(lèi)型T。如果定義了 _UNICODE,則T表示W(wǎng);如果定義了 _MBCS,則T表示A
Cconst 的縮寫(xiě)

使用范例:

      #include <atlconv.h>            void fun()      {          USES_CONVERSION;  // 只需要調用一次,就可以在函數中進(jìn)行多次轉換                    LPCTSTR lp = OLE2CT( L"Hello,你好") );          ... ... ... ...          // 不用顯式釋放 lp 的內存,因為          // 由于 ATL 轉換宏使用棧作為臨時(shí)空間,函數結束后會(huì )自動(dòng)釋放??臻g。      }
  使用 ATL 轉換宏,由于不用釋放臨時(shí)空間,所以使用起來(lái)非常方便。但是考慮到??臻g的尺寸(VC 默認2M),使用時(shí)要注意幾點(diǎn):
    1、只適合于進(jìn)行短字符串的轉換;
    2、不要試圖在一個(gè)次數比較多的循環(huán)體內進(jìn)行轉換;
    3、不要試圖對字符型文件內容進(jìn)行轉換,因為文件尺寸一般情況下是比較大的;
    4、對情況 2 和 3,要使用 MultiByteToWideChar() 和 WideCharToMultiByte();
   
六、VARIANT
  C++、BASIC、Java、Pascal、Script......計算機語(yǔ)言多種多樣,而它們各自又都有自己的數據類(lèi)型,COM 產(chǎn)生目的,其中之一就是要跨語(yǔ)言(注3)。而 VARIANT 數據類(lèi)型就具有跨語(yǔ)言的特性,同時(shí)它可以表示(存儲)任意類(lèi)型的數據。從C語(yǔ)言的角度來(lái)講,VARIANT 其實(shí)是一個(gè)結構,結構中用一個(gè)域(vt)表示------該變量到底表示的是什么類(lèi)型數據,同時(shí)真正的數據則存貯在 union 空間中。結構的定義太長(cháng)了(雖然長(cháng),但其實(shí)很簡(jiǎn)單)大家去看 MSDN 的描述吧,這里給出如何使用的簡(jiǎn)單示例:

學(xué)生:我想用 VARIANT 表示一個(gè)4字節長(cháng)的整數,如何做?
老師:VARIANT v; v.vt=VT_I4; v.lVal=100;

學(xué)生:我想用 VARIANT 表示布爾值“真”,如何做?
老師:VARIANT v; v.vt=VT_BOOL; v.boolVal=VARIANT_TRUE;
學(xué)生:這么麻煩?我能不能 v.boolVal=true; 這樣寫(xiě)?
老師:不可以!因為
 
類(lèi)型字節長(cháng)度假值真值
bool1(char)0(false)1(true)
BOOL4(int)0(FALSE)1(TRUE)
VT_BOOL2(short int)0(VARIANT_FALSE)-1(VARIANT_TRUE)

  所以如果你 v.boolVal=true 這樣賦值,那么將來(lái) if(VARIANT_TRUE==v.boolVal) 的時(shí)候會(huì )出問(wèn)題(-1 != 1)。但是你注意觀(guān)察,任何布爾類(lèi)型的“假”都是0,因此作為一個(gè)好習慣,在做布爾判斷的時(shí)候,不要和“真值”相比較,而要與“假值”做比較。
學(xué)生:謝謝老師,你太牛了。我對老師的敬仰如滔滔江水,連綿不絕......

學(xué)生:我想用 VARIANT 保存字符串,如何做?
老師:VARIANT v; v.vt=VT_BSTR; v.bstrVal=SysAllocString(L"Hello,你好");

學(xué)生:哦......我明白了??墒沁@么操作真夠麻煩的,有沒(méi)有簡(jiǎn)單一些的方法?
老師:有呀,你可以使用現成的包裝類(lèi) CComVariant、COleVariant、_variant_t。比如上面三個(gè)問(wèn)題就可以這樣書(shū)寫(xiě):CComVariant v1(100),v2(true),v3("Hello,你好"); 簡(jiǎn)單了吧?!(注4)

學(xué)生:老師,我再問(wèn)最后一個(gè)問(wèn)題,我如何用 VARIANT 保存一個(gè)數組?
老師:這個(gè)問(wèn)題很復雜,我現在不能告訴你,我現在告訴你怕你印象不深......(注5)
學(xué)生:~!@#$%^&*()......暈!

七、小結
    以上所介紹的內容,是基本功,必須熟練掌握。先到這里吧,休息一會(huì )兒......更多精彩內容,敬請關(guān)注《COM 組件設計與應用(四)》


注1:在后續的 ISupportErrorInfo 接口中介紹。
注2:常見(jiàn)的數據類(lèi)型,請參考 IDL 文件的說(shuō)明。(別著(zhù)急,還沒(méi)寫(xiě)那......嘿嘿)
注3:跨語(yǔ)言就是各種語(yǔ)言中都能使用COM組件。但啥時(shí)候能跨平臺呢?
注4:CComVariant/COlevariant/_variant_t 請參看 MSDN。
注5:關(guān)于安全數組 SafeArray 的使用,在后續的文章中討論。
 



本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
c++字符串完全指引之二 —— 字符串封裝類(lèi) - 悠悠我心
BSTR、LPSTR和LPWSTR 等多種VC字符類(lèi)型分析及各種字符類(lèi)型轉換
vc字符串轉換處理:(絕對精華,收集所有的例子)
有關(guān)數據類(lèi)型轉換
VC常用數據類(lèi)型列表
COM組件設計與應用(九)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久