René Nyffenegger's collection of things on the web | |
René Nyffenegger on Oracle - Most wanted - Feedback
- Follow @renenyffenegger
|
Reading Type Libraries with C++ | ||
A type library contains a binary description of an interface exposed by a COM-component. In this sense, they
contain the same information that is contained in an IDL (Interface Definition Language) file.
Type libraries can be a stand-alone binary files (.tlb), resources in a
dynamic link library or executable file (.dll, .olb, or .exe).
It is possible to read the information within a type library with the
ITypeLib and ITypeInfo interfaces. They can be created
with the ICreateTypeLib and ICreateTypeInfo interfaces. However, the Microsoft IDL compiler (MIDL) is probably the only application
to ever use ICreateType and ICreateTypeInfo .
Type libraries can be registered in which case two entries are found in the registry, on under
HKEY_CLASSES_ROOT\Interface and HKEY_CLASSES_ROOT\TypeLib.
A quickly hacked programm
Here's a quickly hacked programm that allows to read a type library. It just shows the idea, but anyway, someone might find it useful.
A test programm that uses TypeLib.cpp is here.
TypeLib.h
#ifndef TYPE_LIB_H__ #define TYPE_LIB_H__ #include <string> #include <iostream> #include <windows.h> #include "win32_Unicode.h" class TypeLib { public: TypeLib(); bool Open(std::string const& type_lib_file); std::string LibDocumentation(); int NofTypeInfos(); bool CurTypeInfo(int); std::string TypeDocumentation(); // within current type info int NofFunctions(); // within current function short NofParameters(); short NofOptionalParameters(); // within current type info int NofVariables(); std::string FunctionName(); std::string VariableName(); std::string ParameterName(); enum INVOKEKIND { func = DISPATCH_METHOD, get = DISPATCH_PROPERTYGET, put = DISPATCH_PROPERTYPUT, putref = DISPATCH_PROPERTYPUTREF }; INVOKEKIND InvokeKind(); // See <oaidl.h> enum VARIABLEKIND { instance = VAR_PERINSTANCE, static_ = VAR_STATIC, const_ = VAR_CONST, dispatch = VAR_DISPATCH }; VARIABLEKIND VariableKind(); // See <oaidl.h> enum TYPEFLAG { FDEFAULT = IMPLTYPEFLAG_FDEFAULT, FSOURCE = IMPLTYPEFLAG_FSOURCE, FRESTRICTED = IMPLTYPEFLAG_FRESTRICTED, FDEFAULTVTABLE = IMPLTYPEFLAG_FDEFAULTVTABLE, }; // TODO? How to be used correctly bool HasFunctionTypeFlag(TYPEFLAG); // see here bool IsTypeEnum (); bool IsTypeRecord (); bool IsTypeModule (); bool IsTypeInterface(); bool IsTypeDispatch (); bool IsTypeCoClass (); bool IsTypeAlias (); bool IsTypeUnion (); bool IsTypeMax (); std::string ReturnType(); std::string ParameterType(); std::string VariableType(); // Only makes sense if VariableKind == VARIABLEKIND.const_ std::string ConstValue(); bool NextTypeInfo(); bool NextFunction(); bool NextVariable(); bool NextParameter(); bool ParameterIsIn(); bool ParameterIsOut(); bool ParameterIsFLCID(); bool ParameterIsReturnValue(); bool ParameterIsOptional(); bool ParameterHasDefault(); bool ParameterHasCustumData(); private: ITypeLib* typeLib_; int nofTypeInfos_; int curTypeInfo_; ITypeInfo* curITypeInfo_; TYPEATTR* curTypeAttr_; int curTypeIdx_; int curFunc_; int curVar_; int curFuncParam_; int curImplTypeFlags_; FUNCDESC* curFuncDesc_; VARDESC* curVarDesc_; BSTR* funcNames_; unsigned int nofFuncNames_; void ReleaseFuncNames(); void GetFuncNames(); bool ParameterIsHasX(int); bool IsTypeKind(int); std::string TypeDocumentation_(ITypeInfo*); std::string UserdefinedType(HREFTYPE); std::string Type(ELEMDESC const&); }; #endif TypeLib.cpp
#include "TypeLib.h" #include <oaidl.h> #include "VariantHelper.h" TypeLib::TypeLib() : typeLib_ ( 0), nofTypeInfos_ ( 0), curTypeInfo_ (-1), curITypeInfo_ ( 0), curTypeAttr_ ( 0), curFuncDesc_ ( 0), curVarDesc_ ( 0), funcNames_ ( 0) { ::OleInitialize(0); } bool TypeLib::Open(std::string const& type_lib_file) { std::wstring ws_type_lib_file = s2ws(type_lib_file); HRESULT hr = ::LoadTypeLib(ws_type_lib_file.c_str(), &typeLib_); if (hr != S_OK) { std::cout << "Error with LoadTypeLibrary" << std::endl; return false; } nofTypeInfos_ = typeLib_->GetTypeInfoCount(); return true; } bool TypeLib::NextTypeInfo() { curTypeInfo_++; curFunc_ = -1; curVar_ = -1; if (curTypeInfo_ >= nofTypeInfos_) return false; // TODO: warum curTypeAttr_ if (curTypeAttr_ && curITypeInfo_) { curITypeInfo_ -> ReleaseTypeAttr(curTypeAttr_); } if (typeLib_) { HRESULT hr=typeLib_-> GetTypeInfo(curTypeInfo_, &curITypeInfo_); if (hr == S_OK) { curITypeInfo_ -> GetTypeAttr(&curTypeAttr_); return true; } return false; } return false; } bool TypeLib::IsTypeEnum() { return IsTypeKind(TKIND_ENUM); } bool TypeLib::IsTypeRecord() { return IsTypeKind(TKIND_RECORD); } bool TypeLib::IsTypeModule() { return IsTypeKind(TKIND_MODULE); } bool TypeLib::IsTypeInterface() { return IsTypeKind(TKIND_INTERFACE); } bool TypeLib::IsTypeDispatch() { return IsTypeKind(TKIND_DISPATCH); } bool TypeLib::IsTypeCoClass() { return IsTypeKind(TKIND_COCLASS); } bool TypeLib::IsTypeAlias() { return IsTypeKind(TKIND_ALIAS); } bool TypeLib::IsTypeUnion() { return IsTypeKind(TKIND_UNION); } bool TypeLib::IsTypeMax() { return IsTypeKind(TKIND_MAX); } bool TypeLib::IsTypeKind(int i) { TYPEKIND tk = curTypeAttr_->typekind; return i == tk; } std::string TypeLib::LibDocumentation() { if (! typeLib_) return "No Type Library open!"; BSTR name; BSTR doc; unsigned long ctx; HRESULT hr = typeLib_->GetDocumentation( -1, &name, &doc, &ctx, 0 // Help File ); if (hr != S_OK) { std::cout << "GetDocumentation failed" << std::endl; return ""; } std::string sName = ws2s(name); std::string sDoc; if (doc) { sDoc = ws2s(doc); } ::SysFreeString(name); ::SysFreeString(doc ); return sName + ": " + sDoc; } std::string TypeLib::TypeDocumentation() { return TypeDocumentation_(curITypeInfo_); } std::string TypeLib::TypeDocumentation_(ITypeInfo* i) { BSTR name; unsigned long ctx; HRESULT hr = i->GetDocumentation( MEMBERID_NIL, //idx, &name, 0,//&doc, &ctx, 0 // Help File ); if (hr != S_OK) { std::cout << "GetDocumentation failed" << std::endl; return ""; } std::string sName = ws2s(name); ::SysFreeString(name); return sName; } TypeLib::INVOKEKIND TypeLib::InvokeKind() { return static_cast<INVOKEKIND>(curFuncDesc_->invkind); } TypeLib::VARIABLEKIND TypeLib::VariableKind() { return static_cast<VARIABLEKIND>(curVarDesc_->varkind); } bool TypeLib::NextFunction() { ReleaseFuncNames(); curFunc_ ++; curFuncParam_= -1; if (curFunc_ >= curTypeAttr_->cFuncs) return false; if (curFuncDesc_) { curITypeInfo_->ReleaseFuncDesc(curFuncDesc_); } HRESULT hr = curITypeInfo_-> GetFuncDesc(curFunc_, &curFuncDesc_); GetFuncNames(); if (hr != S_OK) { std::cout << "GetFuncDesc failed" << std::endl; return false; } // Is that correct? What is actually a IMPLTYPEFLAG? curITypeInfo_ -> GetImplTypeFlags (curFunc_, &curImplTypeFlags_); return true; } bool TypeLib::HasFunctionTypeFlag(TYPEFLAG tf) { return curImplTypeFlags_ & static_cast<int>(tf); } std::string TypeLib::ConstValue() { if (VariableKind() != const_) { return "VariableKind must be const_"; } //VARIANT v=*(curVarDesc_->lpvarValue); variant v=*(curVarDesc_->lpvarValue); return v.ValueAsString(); } std::string TypeLib::UserdefinedType(HREFTYPE hrt) { std::string tp=""; ITypeInfo* itpi; curITypeInfo_ -> GetRefTypeInfo(hrt, &itpi); std::string ref_type = TypeDocumentation_(itpi); tp += ref_type; return tp; } std::string TypeLib::Type(ELEMDESC const& ed) { TYPEDESC td = ed.tdesc; std::string tp = TypeAsString(td.vt); if (td.vt==VT_PTR) { TYPEDESC ptr_td = *(td.lptdesc); tp += " ("; tp += TypeAsString(ptr_td.vt); if (ptr_td.vt == VT_USERDEFINED) { tp += " ("; HREFTYPE hrt = ptr_td.hreftype; tp += UserdefinedType(hrt); tp += ")"; } tp += ")"; } else if (td.vt == VT_USERDEFINED) { tp += " ("; tp += UserdefinedType(td.hreftype); tp += ")"; } else if (td.vt == VT_SAFEARRAY) { // TODO } return tp; } std::string TypeLib::ParameterType() { ELEMDESC ed = curFuncDesc_->lprgelemdescParam[curFuncParam_]; return Type(ed); } std::string TypeLib::VariableType() { ELEMDESC ed = curVarDesc_->elemdescVar; return Type(ed); } std::string TypeLib::ReturnType() { ELEMDESC ed = curFuncDesc_->elemdescFunc; return Type(ed); } bool TypeLib::NextVariable() { curVar_ ++; // TODO: curVar_->cVars accessed through NofVariables(). if (curVar_ >= curTypeAttr_->cVars) return false; if (curVarDesc_) { curITypeInfo_->ReleaseVarDesc(curVarDesc_); } HRESULT hr = curITypeInfo_->GetVarDesc(curVar_, &curVarDesc_); if (hr != S_OK) { std::cout << "GetVarDesc failed" << std::endl; return false; } return true; } bool TypeLib::NextParameter() { curFuncParam_ ++; if (curFuncParam_ >= NofParameters()) return false; return true; } std::string TypeLib::VariableName() { BSTR varName; unsigned int dummy; HRESULT hr = curITypeInfo_->GetNames(curVarDesc_->memid, &varName, 1, &dummy); if (hr!= S_OK) { return "GetNames failed"; } std::string ret = ws2s(varName); ::SysFreeString(varName); return ret; } std::string TypeLib::ParameterName() { if (1+curFuncParam_ >= static_cast<int>(nofFuncNames_)) return "<nameless>"; BSTR paramName = funcNames_[1+curFuncParam_]; std::string ret = ws2s(paramName); return ret; } // http://doc.ddart.net/msdn/header/include/oaidl.h.html // return ParameterIsHasX(PARAMFLAG_NONE); bool TypeLib::ParameterIsIn() { return ParameterIsHasX(PARAMFLAG_FIN); } bool TypeLib::ParameterIsOut() { return ParameterIsHasX(PARAMFLAG_FOUT); } bool TypeLib::ParameterIsFLCID() { return ParameterIsHasX(PARAMFLAG_FLCID); } bool TypeLib::ParameterIsReturnValue() { return ParameterIsHasX(PARAMFLAG_FRETVAL); } bool TypeLib::ParameterIsOptional() { return ParameterIsHasX(PARAMFLAG_FOPT); } bool TypeLib::ParameterHasDefault() { return ParameterIsHasX(PARAMFLAG_FHASDEFAULT); } bool TypeLib::ParameterHasCustumData() { return ParameterIsHasX(0x40 /*PARAMFLAG_FHASCUSTDATA*/); } bool TypeLib::ParameterIsHasX(int flag) { ELEMDESC e = curFuncDesc_->lprgelemdescParam[curFuncParam_]; return e.paramdesc.wParamFlags & flag; } void TypeLib::ReleaseFuncNames() { if (funcNames_) { for (int i=0;i<static_cast<int>(nofFuncNames_); i++) { ::SysFreeString(funcNames_[i]); } delete [] funcNames_; funcNames_=0; } } void TypeLib::GetFuncNames() { unsigned int nof_names = 1 + NofParameters(); funcNames_ = new BSTR[nof_names]; HRESULT hr = curITypeInfo_->GetNames(curFuncDesc_->memid, funcNames_, nof_names, &nofFuncNames_); if (hr!= S_OK) { std::cout << "GetNames failed" << std::endl; } } std::string TypeLib::FunctionName() { BSTR funcName = funcNames_[0]; std::string ret = ws2s(funcName); return ret; } int TypeLib::NofVariables() { return curTypeAttr_->cVars; } int TypeLib::NofFunctions() { return curTypeAttr_->cFuncs; } int TypeLib::NofTypeInfos() { return nofTypeInfos_; } short TypeLib::NofParameters() { return curFuncDesc_->cParams; } short TypeLib::NofOptionalParameters() { return curFuncDesc_->cParamsOpt; } A test programmtestTypeLib.cpp
// g++ testTypeLib.cpp TypeLib.cpp win32_Unicode.cpp -loleaut32 #include <windows.h> #include <iostream> #include "TypeLib.h" int main() { TypeLib t; if (!t.Open("C:\\Program Files\\Microsoft Office\\Office\\MSWORD9.olb")) { std::cout << "Couldn't open type library" << std::endl; return -1; } std::cout << t.LibDocumentation() << std::endl; int nofTypeInfos = t.NofTypeInfos(); std::cout << "Nof Type Infos: " << nofTypeInfos << std::endl; while (t.NextTypeInfo()) { std::string type_doc = t.TypeDocumentation(); std::cout << std::endl; std::cout << type_doc << std::endl; std::cout << "----------------------------" << std::endl; std::cout << " Interface: "; if (t.IsTypeEnum ()) std::cout << "Enum"; if (t.IsTypeRecord ()) std::cout << "Record"; if (t.IsTypeModule ()) std::cout << "Module"; if (t.IsTypeInterface()) std::cout << "Interface"; if (t.IsTypeDispatch ()) std::cout << "Dispatch"; if (t.IsTypeCoClass ()) std::cout << "CoClass"; if (t.IsTypeAlias ()) std::cout << "Alias"; if (t.IsTypeUnion ()) std::cout << "Union"; if (t.IsTypeMax ()) std::cout << "Max"; std::cout << std::endl; int nofFunctions=t.NofFunctions(); int nofVariables=t.NofVariables(); std::cout << " functions: " << nofFunctions << std::endl; std::cout << " variables: " << nofVariables << std::endl; while (t.NextFunction()) { std::cout << std::endl; std::cout << " Function : " << t.FunctionName() << std::endl; std::cout << " returns : " << t.ReturnType() << std::endl; std::cout << " flags : "; if (t.HasFunctionTypeFlag(TypeLib::FDEFAULT )) std::cout << "FDEFAULT " ; if (t.HasFunctionTypeFlag(TypeLib::FSOURCE )) std::cout << "FSOURCE " ; if (t.HasFunctionTypeFlag(TypeLib::FRESTRICTED )) std::cout << "FRESTRICTED " ; if (t.HasFunctionTypeFlag(TypeLib::FDEFAULTVTABLE)) std::cout << "FDEFAULTVTABLE "; std::cout << std::endl; TypeLib::INVOKEKIND ik = t.InvokeKind(); switch (ik) { case TypeLib::func: std::cout <<" invoke kind: function" << std::endl; break; case TypeLib::put: std::cout <<" invoke kind: put" << std::endl; break; case TypeLib::get: std::cout <<" invoke kind: get" << std::endl; break; case TypeLib::putref: std::cout <<" invoke kind: put ref" << std::endl; break; default: std::cout <<" invoke kind: ???" << std::endl; } std::cout << " params : " << t.NofParameters() << std::endl; std::cout << " params opt : " << t.NofOptionalParameters() << std::endl; while (t.NextParameter()) { std::cout << " Parameter : " << t.ParameterName(); std::cout << " type = " << t.ParameterType(); if (t.ParameterIsIn ()) std::cout << " in"; if (t.ParameterIsOut ()) std::cout << " out"; if (t.ParameterIsFLCID ()) std::cout << " flcid"; if (t.ParameterIsReturnValue()) std::cout << " ret"; if (t.ParameterIsOptional ()) std::cout << " opt"; if (t.ParameterHasDefault ()) std::cout << " def"; if (t.ParameterHasCustumData()) std::cout << " cust"; std::cout << std::endl; } } while (t.NextVariable()) { std::cout << " Variable : " << t.VariableName() << std::endl; std::cout << " Type : " << t.VariableType(); TypeLib::VARIABLEKIND vk = t.VariableKind(); switch (vk) { case TypeLib::instance: std::cout << " (instance)" << std::endl; break; case TypeLib::static_ : std::cout << " (static)" << std::endl; break; case TypeLib::const_ : std::cout << " (const "; std::cout << t.ConstValue() << ")" << std::endl; break; case TypeLib::dispatch: std::cout << " (dispatch)" << std::endl; break; default: std::cout << " variable kind: unknown" << std::endl; } } } return 0; } |