#include <olectl.h> #include <stdio.h> bool IsEnumerated(ITypeInfo* pTypeInfo) { bool ok = false; if (pTypeInfo) { LPTYPEATTR pTypeAttr = 0; pTypeInfo->GetTypeAttr(&pTypeAttr); if (pTypeAttr != 0) { ok = (pTypeAttr->typekind == TKIND_ENUM); pTypeInfo->ReleaseTypeAttr(pTypeAttr); } } return ok; } bool IsBool(IDispatch* pDispatch, DISPID di) { bool ok = false; VARIANT val; VariantInit(&val); DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; HRESULT hr = pDispatch->Invoke(di, IID_NULL, LOCALE_USER_DEFAULT, \ DISPATCH_PROPERTYGET, &dispparamsNoArgs, &val, NULL, NULL); ok = (SUCCEEDED(hr) && val.vt == VT_BOOL); VariantClear(&val); return ok; } bool IsPerPropertyBrowse(IDispatch* pDispatch, DISPID di) { bool ok = false; IPerPropertyBrowsing* pBrowse = 0; HRESULT hr = pDispatch->QueryInterface(IID_IPerPropertyBrowsing, (void**) &pBrowse); if (SUCCEEDED(hr)) { CALPOLESTR castr; CADWORD cadw; ZeroMemory(&castr, sizeof(castr)); ZeroMemory(&cadw, sizeof(cadw)); hr = pBrowse->GetPredefinedStrings(di, &castr, &cadw); if (hr == S_OK) { ULONG i; ok = true; for (i = 0; i < castr.cElems; ++i) { char buff[32]; WideCharToMultiByte(866, 0, castr.pElems[i], -1, buff, 32, 0, 0); printf("\n\t%s", buff); } CoTaskMemFree(cadw.pElems); for (i = 0; i < castr.cElems; ++i) { CoTaskMemFree(castr.pElems[i]); // SysFreeString(castr.pElems[i]); } CoTaskMemFree(castr.pElems); } pBrowse->Release(); } return ok; } bool IsColor(ITypeInfo* pTypeInfo, DISPID di) { if (di == DISPID_BACKCOLOR || di == DISPID_FORECOLOR \ || di == DISPID_BORDERCOLOR || di == DISPID_FILLCOLOR) { return true; } bool ok = false; if (pTypeInfo != 0) { LPTYPEATTR pTypeAttr = 0; pTypeInfo->GetTypeAttr(&pTypeAttr); if (pTypeAttr) { if (pTypeAttr->typekind == TKIND_ALIAS) { ITypeLib *pTypeLib = 0; UINT nIndex; HRESULT hr = pTypeInfo->GetContainingTypeLib(&pTypeLib, &nIndex); if (SUCCEEDED(hr)) { BSTR bstrName; BSTR bstrDoc; hr = pTypeLib->GetDocumentation(nIndex, &bstrName, &bstrDoc, NULL, NULL); if (SUCCEEDED(hr)) { ok = (0 == lstrcmpW(bstrName, L"OLE_COLOR")); } if (bstrName) SysFreeString(bstrName); if (bstrDoc) SysFreeString(bstrDoc); pTypeLib->Release(); } } pTypeInfo->ReleaseTypeAttr(pTypeAttr); } } return ok; } bool IsFont(ITypeInfo* pTypeInfo, DISPID di) { if (di == DISPID_FONT) return true; bool ok = false; if (pTypeInfo != 0) { LPTYPEATTR pTypeAttr = 0; pTypeInfo->GetTypeAttr(&pTypeAttr); if (pTypeAttr) { ok = InlineIsEqualGUID(pTypeAttr->guid, IID_IFontDisp); pTypeInfo->ReleaseTypeAttr(pTypeAttr); } } return ok; } bool RegisterProperty(LPDISPATCH pDispatch, DISPID di, \ LPTYPEINFO pTypeInfo, LPTYPEINFO pUserTypeInfo) { BSTR bstrName = NULL; BSTR bstrDocString = NULL; HRESULT hr = pTypeInfo->GetDocumentation(di, &bstrName, &bstrDocString, NULL, NULL); if (SUCCEEDED(hr)) { printf("%S: ", bstrName); if (IsEnumerated(pUserTypeInfo)) { printf("enum"); } else if (IsBool(pDispatch, di)) { printf("bool"); } else if (IsPerPropertyBrowse(pDispatch, di)) { // printf("browse"); } else if (IsColor(pUserTypeInfo, di)) { printf("color"); } else if (IsFont(pUserTypeInfo, di)) { printf("font"); } else { printf("generic"); } printf("\n"); if (bstrName) SysFreeString(bstrName); if (bstrDocString) SysFreeString(bstrDocString); } return false; } VARTYPE GetUserDefinedType(LPTYPEINFO pTI, HREFTYPE hrt) { VARTYPE vt = VT_USERDEFINED; LPTYPEINFO pRTI = 0; HRESULT hr = pTI->GetRefTypeInfo(hrt, &pRTI); if (SUCCEEDED(hr)) { LPTYPEATTR pTA = 0; hr = pRTI->GetTypeAttr(&pTA); if (pTA) { if (SUCCEEDED(hr) && pTA->typekind == TKIND_ALIAS) { if (pTA->tdescAlias.vt == VT_USERDEFINED) { vt = GetUserDefinedType(pRTI, pTA->tdescAlias.hreftype); } else { vt = pTA->tdescAlias.vt; } } pRTI->ReleaseTypeAttr(pTA); } pRTI->Release(); } return vt; } HRESULT GetEnumTypeInfo(LPTYPEINFO pTI, HREFTYPE hrt, ITypeInfo** ppEnumInfo) { *ppEnumInfo = 0; LPTYPEINFO pRTI = 0; HRESULT hr = pTI->GetRefTypeInfo(hrt, &pRTI); if (SUCCEEDED(hr)) { hr = E_NOINTERFACE; LPTYPEATTR pTA = 0; pRTI->GetTypeAttr(&pTA); if (pTA) { switch (pTA->typekind) { case TKIND_ALIAS: if (pTA->tdescAlias.vt == VT_USERDEFINED) { hr = GetEnumTypeInfo(pRTI, pTA->tdescAlias.hreftype, ppEnumInfo); } else { *ppEnumInfo = pRTI; pRTI->AddRef(); hr = S_OK; } break; case TKIND_ENUM: case TKIND_DISPATCH: { *ppEnumInfo = pRTI; pRTI->AddRef(); hr = S_OK; } break; } pRTI->ReleaseTypeAttr(pTA); } pRTI->Release(); } return hr; } bool QueryProperty(LPDISPATCH pDispatch, LPTYPEINFO pTypeInfo, LPFUNCDESC pFuncDesc) { bool ok = false; switch (pFuncDesc->elemdescFunc.tdesc.vt) { case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4: case VT_R4: case VT_R8: case VT_CY: case VT_DATE: case VT_BSTR: case VT_ERROR: case VT_BOOL: case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1: case VT_UI2: case VT_UI4: case VT_INT: case VT_UINT: ok = RegisterProperty(pDispatch, pFuncDesc->memid, pTypeInfo, NULL); break; case VT_USERDEFINED: { HREFTYPE hRefType = pFuncDesc->elemdescFunc.tdesc.hreftype; VARTYPE vt = VT_USERDEFINED; LPTYPEINFO pUserTypeInfo = 0; HRESULT hr = GetEnumTypeInfo(pTypeInfo, hRefType, &pUserTypeInfo); if (FAILED(hr)) { vt = GetUserDefinedType(pTypeInfo, hRefType); } ok = RegisterProperty(pDispatch, pFuncDesc->memid, pTypeInfo, pUserTypeInfo); if (pUserTypeInfo) { pUserTypeInfo->Release(); } } break; case VT_PTR: { TYPEDESC *pTypeDesc = pFuncDesc->elemdescFunc.tdesc.lptdesc; if (pTypeDesc->vt == VT_USERDEFINED) { LPTYPEINFO pUserTypeInfo = 0; HRESULT hr = GetEnumTypeInfo(pTypeInfo, pTypeDesc->hreftype, &pUserTypeInfo); if (SUCCEEDED(hr) && pUserTypeInfo != 0) { LPTYPEATTR pTypeAttr = 0; if (SUCCEEDED(pUserTypeInfo->GetTypeAttr(&pTypeAttr))) { if (InlineIsEqualGUID(pTypeAttr->guid, IID_IFontDisp)) { ok = RegisterProperty(pDispatch, pFuncDesc->memid, pTypeInfo, pUserTypeInfo); } pUserTypeInfo->ReleaseTypeAttr(pTypeAttr); } pUserTypeInfo->Release(); } } } break; } return ok; } HRESULT QueryControl() { CLSID cid; HRESULT hr = CLSIDFromProgID(OLESTR("MSCAL.Calendar"), &cid); if (FAILED(hr)) { return hr; } LPDISPATCH pDispatch = 0; hr = CoCreateInstance(cid, NULL, CLSCTX_INPROC_SERVER, \ IID_IDispatch, (void**) &pDispatch); if (FAILED(hr)) { return hr; } LPTYPEINFO pTypeInfo = 0; hr = pDispatch->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &pTypeInfo); if (FAILED(hr)) { pDispatch->Release(); return hr; } LPTYPEATTR pTypeAttr = 0; hr = pTypeInfo->GetTypeAttr(&pTypeAttr); if (FAILED(hr)) { pTypeInfo->Release(); pDispatch->Release(); } if (pTypeAttr->typekind == TKIND_INTERFACE) { // If the TKIND_DISPATCH type description is for a dual interface, // the TKIND_INTERFACE type description can be obtained by calling // GetRefTypeOfImplType with an index of -1, and by passing the returned // pRefType handle to GetRefTypeInfo to retrieve the type information. HREFTYPE hRefType; hr = pTypeInfo->GetRefTypeOfImplType(-1, &hRefType); if (SUCCEEDED(hr)) { LPTYPEINFO pRefTypeInfo = 0; hr = pTypeInfo->GetRefTypeInfo(hRefType, &pRefTypeInfo); if (SUCCEEDED(hr)) { pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); pTypeInfo = pRefTypeInfo; hr = pTypeInfo->GetTypeAttr(&pTypeAttr); if (FAILED(hr)) { pTypeInfo->Release(); pDispatch->Release(); return hr; } } } } // sweep through looking for property put const int MAX_MEMBERID = 0x100; MEMBERID memberid[MAX_MEMBERID], *pMI = memberid; for (int i = 0; i < pTypeAttr->cFuncs; ++i) { LPFUNCDESC pFuncDesc = 0; hr = pTypeInfo->GetFuncDesc(i, &pFuncDesc); if (SUCCEEDED(hr)) { if (pFuncDesc->invkind & INVOKE_PROPERTYPUT) { if (pMI - memberid < MAX_MEMBERID) { *pMI++ = pFuncDesc->memid; } else { pTypeInfo->Release(); pDispatch->Release(); return E_OUTOFMEMORY; } } pTypeInfo->ReleaseFuncDesc(pFuncDesc); } } // now find prop get methods for (int i = 0; i < pTypeAttr->cFuncs; ++i) { LPFUNCDESC pFuncDesc = 0; hr = pTypeInfo->GetFuncDesc(i, &pFuncDesc); if (SUCCEEDED(hr)) { if ((pFuncDesc->invkind & INVOKE_PROPERTYGET) != 0 && (pFuncDesc->wFuncFlags & (FUNCFLAG_FRESTRICTED | FUNCFLAG_FHIDDEN | FUNCFLAG_FNONBROWSABLE)) == 0) { for (MEMBERID *pMI2 = memberid; pMI2 < pMI; ++pMI2) { if (pFuncDesc->memid == *pMI2) { QueryProperty(pDispatch, pTypeInfo, pFuncDesc); break; } } } pTypeInfo->ReleaseFuncDesc(pFuncDesc); } } pTypeInfo->ReleaseTypeAttr(pTypeAttr); pTypeInfo->Release(); pDispatch->Release(); return S_OK; } int main() { HRESULT hr = OleInitialize(NULL); if (SUCCEEDED(hr)) { hr = QueryControl(); OleUninitialize(); } return (SUCCEEDED(hr)? 0: 1); } |