|
Posted on 2006-10-05 18:26 奔跑的阿甘 閱讀(2071) 評論(0) 編輯 收藏 引用 所屬分類: COM/ATL
COM數據類型 Michael 2006年10月5日 本文根據DON BOX大師《Essential COM》第2.11章節文章,對COM中IDL的數據類型的用法進行了總結。
IDL數據類型的設計思想是要保證類型的“語言獨立”和“平臺獨立”,例如它需要能被C++/VB/Java等語言和Windows(各版本)和Solaris等平臺識別和支持。
1。基本類型 全是小寫的字符表示。 包括:boolean, byte, small, short, long, hyper, float, double, char, wchar_t, enum, 接口指針。這些類型我們并不陌生。
2。OLECHAR類型 這是COM中的字符類型。例如:HRESULT Method([in,string] const OLECHAR* pwsz);"string"屬性表示pwsz是個OLECHAR數組。 在WIN32/Solaris平臺上OLECHAR只是簡單地被定義為wchar_t類型。 我們可以通過COM提供的宏OLESTR把一個普通的字符串轉換為OLECHAR*類型:const OLECHAR *pwsz = OLESTR("Hello")。
WIN32提供的TCHAR類型隨著預編譯宏的定義而不同,為防止代碼的冗余繁瑣,Don Box大師編寫了相關類和函數,用于把TCHAR*類型轉換為OLECHAR*類型。 ustring.h提供了_U,_UNCC類用于把TCHAR*類型轉換為OLECHAR*類型,并提供了ustrncpy等串操作的重載版本(接受char,wchar_t為參數類型)。
  ??1 /**//////////////////////////////////////////////////////////////////////////////// ??2 // ??3 //?ustring.h?-?Copyright?1997,?Don?Box ??4 // ??5 //?This?file?contains?overloaded?ustrcpy,?ustrcat,?and?ustrlen?that ??6 //?take?either?wchar_t?or?char?strings?for?either?argument?and?map?to ??7 //?the?appropriate?CRT?routine?to?do?the?work.?The?routines?are?inlined ??8 //?and?incur?no?additional?overhead. ??9 // ?10 //?????size_t?ustrlen(const?uchar?*p);? ?11 //?????uchar?*ustrcpy(uchar?*p1,?const?uchar?*p2);? ?12 //?????uchar?*ustrcat(uchar?*p1,?const?uchar?*p2);? ?13 // ?14 //?where?uchar?=?{?wchar_t?,?char?} ?15 // ?16 //?This?file?contains?the?prototypes?for?several?conversion?routines? ?17 //?that?are?used?by?the?String816?class?for?duplicating/converting?strings ?18 //?on?the?fly. ?19 // ?20 //?????uxdup(const?char?*psz)?-?returns?a?new-ed?wchar_t?string?based?on?psz ?21 //?????uxdup(const?wchar_t?*psz)?-?returns?a?new-ed?char?string?based?on?psz ?22 //????? ?23 //?Finally,?this?file?contains?two?class?definitions: ?24 //? ?25 //?????_U?-?converts?const?uchar?*?to?const?uchar?* ?26 //?????_UNCC?-?converts?const?uchar?*?to?uchar?*?(needed?for?non-const?correct?code) ?27 // ?28 //?Usage: ?29 /**//* ?30 ?31 void?f(const?OLECHAR?*pwsz,?HWND?hwnd) ?32 { ?33 ????TCHAR?sz[MAX_PATH]; ?34 ????GUID?guid; ?35 ????ustrcpy(sz,?pwsz);?//?overloads?to?correct?copy/conversion?routine ?36 ????SetWindowText(hwnd,?_U(pwsz));?//?_U?temporarily?dups?buffer?if?needed ?37 ????GetWindowText(hwnd,?sz,?MAX_PATH); ?38 ????CLSIDFromString(_UNCC(sz),?&guid);?//?_UNCC?needed?because?api?non-const-correct ?39 } ?40 ?41 */ ?42 ?43 #ifndef?_USTR_H ?44 #define?_USTR_H ?45 ?46 #include?<limits.h> ?47 ?48 inline?size_t?ustrlen(const?wchar_t?*psz) ?49  { ?50 ????return?wcslen(psz); ?51 } ?52 ?53 inline?size_t?ustrlen(const?char?*psz) ?54  { ?55 ????return?strlen(psz); ?56 } ?57 ?58 inline?char?*ustrcpy(char?*pszTarget,?const?wchar_t?*pszSrc) ?59  { ?60 ????return?wcstombs(pszTarget,?pszSrc,?INT_MAX),?pszTarget; ?61 } ?62 ?63 inline?wchar_t?*ustrcpy(wchar_t?*pszTarget,?const?wchar_t?*pszSrc) ?64  { ?65 ????return?wcscpy(pszTarget,?pszSrc),?pszTarget; ?66 } ?67 ?68 inline?char?*ustrcpy(char?*pszTarget,?const?char?*pszSrc) ?69  { ?70 ????return?strcpy(pszTarget,?pszSrc),?pszTarget; ?71 } ?72 ?73 inline?wchar_t?*ustrcpy(wchar_t?*pszTarget,?const?char?*pszSrc) ?74  { ?75 ????return?mbstowcs(pszTarget,?pszSrc,?INT_MAX),?pszTarget; ?76 } ?77 ?78 inline?char?*ustrcat(char?*pszTarget,?const?wchar_t?*pszSrc) ?79  { ?80 ????return?wcstombs(pszTarget?+?ustrlen(pszTarget),?pszSrc,?INT_MAX),?pszTarget; ?81 } ?82 ?83 inline?wchar_t?*ustrcat(wchar_t?*pszTarget,?const?wchar_t?*pszSrc) ?84  { ?85 ????return?wcscat(pszTarget,?pszSrc); ?86 } ?87 ?88 inline?char?*ustrcat(char?*pszTarget,?const?char?*pszSrc) ?89  { ?90 ????return?strcat(pszTarget,?pszSrc); ?91 } ?92 ?93 inline?wchar_t?*ustrcat(wchar_t?*pszTarget,?const?char?*pszSrc) ?94  { ?95 ????return?mbstowcs(pszTarget?+?ustrlen(pszTarget),?pszSrc,?INT_MAX),?pszTarget; ?96 } ?97 ?98 //?these?two?routines?are?equivalent?to?strdup?but?convert? ?99 //?instead?of?just?copying 100 101 wchar_t?*uxdup(const?char?*psz); 102 char?*uxdup(const?wchar_t?*pwsz); 103 104 105 //?String816?maps?const?wchar_t?*?and?const?char?*?to? 106 //?either?const?wchar_t?*?or?const?char?*?depending?on?context 107 class?String816 108  { 109 ????wchar_t?*m_pwsz; 110 ????char????*m_psz; 111 ????BOOL?????m_bIsWide; 112 public: 113 ????String816(const?char?*psz) 114 ????????:?m_pwsz(0),?m_psz((char*)psz),?m_bIsWide(FALSE) 115 ???? { 116 ????} 117 118 ????String816(const?wchar_t?*pwsz) 119 ????????:?m_pwsz((wchar_t*)pwsz),?m_psz(0),?m_bIsWide(TRUE) 120 ???? { 121 ????} 122 123 ????operator?const?wchar_t?*?(void) 124 ???? { 125 ????????if?(!m_bIsWide?&&?m_pwsz?==?0) 126 ????????????m_pwsz?=?uxdup(m_psz); 127 ????????return?m_pwsz; 128 ????} 129 130 ????operator?const?char?*?(void) 131 ???? { 132 ????????if?(m_bIsWide?&&?m_psz?==?0) 133 ????????????m_psz?=?uxdup(m_pwsz); 134 ????????return?m_psz; 135 ????} 136 137 ????~String816(void) 138 ???? { 139 ????????if?(m_bIsWide?&&?m_psz) 140 ????????????free(m_psz); 141 ????????else?if?(!m_bIsWide?&&?m_pwsz) 142 ????????????free(m_pwsz); 143 ????} 144 }; 145 146 typedef?String816?_U; 147 //?class?_UNCC?adds?non-const?conversion?operators?to?String816 148 class?_UNCC?:?public?String816 149  { 150 public: 151 ????_UNCC(const?char?*psz) 152 ????????:?String816(psz) 153 ???? { 154 ????} 155 156 ????_UNCC(const?wchar_t?*pwsz) 157 ????????:?String816(pwsz) 158 ???? { 159 ????} 160 161 ????operator?wchar_t?*?(void) 162 ???? { 163 ????????return?(wchar_t*)operator?const?wchar_t?*(); 164 ????} 165 166 ????operator?char?*?(void) 167 ???? { 168 ????????return?(char*)operator?const?char?*(); 169 ????} 170 171 }; 172 173 174 #endif 175 176 ---------------------------------------------- 177 /**//////////////////////////////////////////////////////////////////////////////// 178 // 179 //?ustring.cpp?-?Copyright?1997,?Don?Box 180 // 181 //?This?file?contains?the?implementation?of?several?conversion?routines? 182 //?that?are?used?by?the?String816?class?for?duplicating/converting?strings 183 //?on?the?fly. 184 // 185 //?????uxdup(const?char?*psz)?-?returns?a?new-ed?wchar_t?string?based?on?psz 186 //?????uxdup(const?wchar_t?*psz)?-?returns?a?new-ed?char?string?based?on?psz 187 //????? 188 189 #ifndef?_USTRING_CPP 190 #define?_USTRING_CPP 191 192 wchar_t?*uxdup(const?char?*psz) 193  { 194 ????size_t?cch?=?strlen(psz)?+?1; 195 ????wchar_t?*pwszResult?=?(wchar_t*)malloc(cch?*?sizeof(wchar_t)); 196 ????if?(pwszResult) 197 ????????mbstowcs(pwszResult,?psz,?cch); 198 ????return?pwszResult; 199 } 200 201 char?*uxdup(const?wchar_t?*pwsz) 202  { 203 ????size_t?cch?=?wcslen(pwsz)?+?1; 204 ????char?*pszResult?=?(char*)malloc(sizeof(char)?*?cch); 205 ????if?(pszResult) 206 ????????wcstombs(pszResult,?pwsz,?cch); 207 ????return?pszResult; 208 } 209 210 #endif
3。BSTR BSTR是一個LENGTH-PREFIXED,NULL-TERMINATED的OLECHAR字符串。 在JAVA,VB中使用的COM接口文本參數都是BSTR類型。
BSTR的內存管理問題:COM提供了若干API用于分配釋放BSTR內存,包括:
 BSTR內存管理函數 ?1 //?分配和初始化BSTR ?2 BSTR?SysAllocString(const?OLECHAR?*psz); ?3 BSTR?SysAllocStringLen(const?OLECHAR?*psz,?UINT?cch); ?4 ?5 //?重分配和初始化BSTR ?6 INT?SysReAllocString(BSTR?*pbstr,?const?OLECHAR?*psz); ?7 INT?SysReAllocStringLen(BSTR?*pbstr,?const?OLECHAR?*psz,?UINT?cch); ?8 ?9 //?釋放BSTR 10 void?SysFreeString(BSTR?bstr); 11 12 //?長度前綴轉換為字符或字節 13 UINT?SysStringLen(BSTR?bstr); 14 UINT?SysStringByteLen(BSTR?bstr); BSTR的內存由誰分配:若BSTR作為接口方法的傳入參數,則調用方負責分配和釋放;若作為傳出參數,則接口對象負責分配,調用方負責釋放。 當BSTR作為傳入參數時,可采用以下類似前面_U,_UNCC的_UBSTR類來簡化代碼:
 _UBSTR ?1 class?_UBSTR? { ?2 ????BSTR?m_bstr; ?3 public: ?4 ????_UBSTR(const?char?*psz) ?5 ????????:?m_bstr(SysAllocStringLen(0,?strlen(psz)))? { ?6 ????mbstowcs(m_bstr,?psz,?INT_MAX); ?7 ????} ?8 ???? ?9 ????_UBSTR(const?wchar_t?*pwsz) 10 ????????:?m_bstr(SysAllocString(pwsz))? {} 11 ???? 12 ????operator?BSTR?(void)?const? {?return?m_bstr;} 13 ????~_UBSTR(void)? {SysFreeString(m_bstr);} 14 };
4。VARIANT, VARIANTARG ??? VARIANT是個UNION類型,它容納前面提到的基本類型中的一個子集類型,具體支持哪個類型由對應的鑒別器指定,如VT_I2對應short類型。 ??? VARIANTARG作為方法參數,VARIANT作為方法結果,但是兩個是同一個聯合,僅僅名稱不同而已。
 VARIANT管理函數 ?1 //請參考MSDN獲得詳細含義 ?2 ?3 void?VariantInit(VARIANTARG?*pvarg); ?4 ?5 HRESULT?VariantClear(VARIANTARG?*pvarg); ?6 ?7 HRESULT?VariantCopy(VARIANTARG?*plhs,?VARIANTARG?*prhs); ?8 ?9 HRESULT?VariantCopyInd(VARIANT?*plhs,?VARIANTARG?*prhs); 10 11 HRESULT?VariantChangeType(VARIANTARG?*plhs,?VARIANTARG?*prhs,?USHORT?wFlags,?VARTYPE?vtlhs); 12 13 HRESULT?VariantChangeTypeEx(VARIANTARG?*?plhs,?VARIANTARG?*prhs,?LCID?lcid,?USHORT?wFlags,?VARTYPE?vtlhs); 14 ?  EXAMPLE 1 1 //向接口方法傳遞一整型 2 3 VARIANT?var; 4 VariantInit(&var); 5 V_VT(&var)?=?VT_I4;??//設置DISCRIMINATOR(鑒別器) 6 V_I4(&var)?=?100;????//傳遞整型值100 7 8 pObject->CallIt(var);//調用方法 9 VariantClear(&var);??//釋放資源?  EXAMPLE 2 ?1 //?CallIt方法內部采用字符串的VARIANT ?2 //?所以調用了VARIANT?API進行了類型轉換 ?3 ?4 STDMETHODIMP?MyObject::CallIt(/**//*[in]*/VARIANT?var)? { ?5 ????VARIANT?var2; ?6 ????VariantInit(&var2); ?7 ????HRESULT?hr?=?VariantChangeType(&var2,?&var,?0,?VT_BSTR); ?8 ????if?(SUCCEEDED(hr))? { ?9 ????????ustrcpy(m_sz,?SAFEBSTR(V_BSTR(&var2))); 10 ????????VariantClear(&var2); 11 ????} 12 ????return?hr; 13 } 14 15 inline?OLECHAR?*SAFEBSTR(BSTR?bstr)? { 16 ????return?b?b:OLESTR(""); 17 }5。COM接口 COM接口也可以作為方法參數進行傳遞,如: HRESULT GetObject([out] IDog **ppDog); HRESULT GetObject([in] REFIID riid, [out, iid_is(riid)]?IUnknown **ppv); HRESULT GetObject([in] REFIID riid, [out, iid_is(riid)] void **ppv); (優先選擇)
【完】
|