|
Posted on 2006-10-05 18:26 奔跑的阿甘 阅读(2050) 评论(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 31void 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 48inline size_t ustrlen(const wchar_t *psz) 49{ 50 return wcslen(psz); 51} 52 53inline size_t ustrlen(const char *psz) 54{ 55 return strlen(psz); 56} 57 58inline char *ustrcpy(char *pszTarget, const wchar_t *pszSrc) 59{ 60 return wcstombs(pszTarget, pszSrc, INT_MAX), pszTarget; 61} 62 63inline wchar_t *ustrcpy(wchar_t *pszTarget, const wchar_t *pszSrc) 64{ 65 return wcscpy(pszTarget, pszSrc), pszTarget; 66} 67 68inline char *ustrcpy(char *pszTarget, const char *pszSrc) 69{ 70 return strcpy(pszTarget, pszSrc), pszTarget; 71} 72 73inline wchar_t *ustrcpy(wchar_t *pszTarget, const char *pszSrc) 74{ 75 return mbstowcs(pszTarget, pszSrc, INT_MAX), pszTarget; 76} 77 78inline char *ustrcat(char *pszTarget, const wchar_t *pszSrc) 79{ 80 return wcstombs(pszTarget + ustrlen(pszTarget), pszSrc, INT_MAX), pszTarget; 81} 82 83inline wchar_t *ustrcat(wchar_t *pszTarget, const wchar_t *pszSrc) 84{ 85 return wcscat(pszTarget, pszSrc); 86} 87 88inline char *ustrcat(char *pszTarget, const char *pszSrc) 89{ 90 return strcat(pszTarget, pszSrc); 91} 92 93inline 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 101wchar_t *uxdup(const char *psz); 102char *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 107class String816 108{ 109 wchar_t *m_pwsz; 110 char *m_psz; 111 BOOL m_bIsWide; 112public: 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 146typedef String816 _U; 147// class _UNCC adds non-const conversion operators to String816 148class _UNCC : public String816 149{ 150public: 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 192wchar_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 201char *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 2BSTR SysAllocString(const OLECHAR *psz); 3BSTR SysAllocStringLen(const OLECHAR *psz, UINT cch); 4 5// 重分配和初始化BSTR 6INT SysReAllocString(BSTR *pbstr, const OLECHAR *psz); 7INT SysReAllocStringLen(BSTR *pbstr, const OLECHAR *psz, UINT cch); 8 9// 释放BSTR 10void SysFreeString(BSTR bstr); 11 12// 长度前缀转换为字符或字节 13UINT SysStringLen(BSTR bstr); 14UINT SysStringByteLen(BSTR bstr); BSTR的内存由谁分配:若BSTR作为接口方法的传入参数,则调用方负责分配和释放;若作为传出参数,则接口对象负责分配,调用方负责释放。 当BSTR作为传入参数时,可采用以下类似前面_U,_UNCC的_UBSTR类来简化代码:
_UBSTR 1class _UBSTR { 2 BSTR m_bstr; 3public: 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 3void VariantInit(VARIANTARG *pvarg); 4 5HRESULT VariantClear(VARIANTARG *pvarg); 6 7HRESULT VariantCopy(VARIANTARG *plhs, VARIANTARG *prhs); 8 9HRESULT VariantCopyInd(VARIANT *plhs, VARIANTARG *prhs); 10 11HRESULT VariantChangeType(VARIANTARG *plhs, VARIANTARG *prhs, USHORT wFlags, VARTYPE vtlhs); 12 13HRESULT VariantChangeTypeEx(VARIANTARG * plhs, VARIANTARG *prhs, LCID lcid, USHORT wFlags, VARTYPE vtlhs); 14 EXAMPLE 1 1//向接口方法传递一整型 2 3VARIANT var; 4VariantInit(&var); 5V_VT(&var) = VT_I4; //设置DISCRIMINATOR(鉴别器) 6V_I4(&var) = 100; //传递整型值100 7 8pObject->CallIt(var);//调用方法 9VariantClear(&var); //释放资源 EXAMPLE 2 1// CallIt方法内部采用字符串的VARIANT 2// 所以调用了VARIANT API进行了类型转换 3 4STDMETHODIMP 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 15inline 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); (优先选择)
【完】
|