12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517 |
- unit typelib;
- {$mode objfpc}{$H+}
- { Typelib import routines.
- Creates freepascal bindings for COM objects stored in .tlb, .dll, .exe or .olb files.
- Copyright (C) 2011 Ludo Brands
- This library is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published by
- the Free Software Foundation; either version 2 of the License, or (at your
- option) any later version with the following modification:
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent modules,and
- to copy and distribute the resulting executable under terms of your choice,
- provided that you also meet, for each linked independent module, the terms
- and conditions of the license of that module. An independent module is a
- module which is not derived from or based on this library. If you modify
- this library, you may extend this exception to your version of the library,
- but you are not obligated to do so. If you do not wish to do so, delete this
- exception statement from your version.
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
- for more details.
- You should have received a copy of the GNU Library General Public License
- along with this library; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- }
- interface
- uses
- Classes, SysUtils,comobj,activex,windows;
- {
- Reads type information from 'FileName' and converts it in a freepascal binding unit. The
- contents of the unit is returned as the function result.
- Returns in 'sUnitName' the unit name with '.pas' extension.
- Appends to 'slDependencies' the filenames of the additional typelibs needed.
- If bActiveX is true an ActiveXContainer descendant is created with the evenual OnEvent hooks
- If bActiveX is false and an event source is found an TEventSink descendant is created with the OnEvent hooks
- By default, the type library is extracted from the first resource of type ITypeLib.
- To load a different type of library resource, append an integer index to 'FileName'.
- Example: C:\WINDOWS\system32\msvbvm60.dll\3
- }
- function ImportTypelib(FileName: WideString;var sUnitName:string;var slDependencies:TStringList;
- bActiveX:boolean):string;
- Type
- { TTypeLibImporter }
- TTypeLibImporter = Class(TComponent)
- private
- FActiveX: Boolean;
- FAppendVersionNumber: Boolean;
- FDependencies: TStringList;
- FUnitSource: TStringList;
- FInputFileName: WideString;
- FOutputFileName: String;
- FUnitname: string;
- FUses : TStrings;
- FHeader : TStrings;
- FInterface : TStrings;
- FImplementation : TStrings;
- FTypes : TStrings;
- FEventDisp : TStrings;
- FEventIID : TStrings;
- FEventSignatures: TStrings;
- FEventFunctions: TStrings;
- FEventProperties: TStrings;
- FEventImplementations: TStrings;
- function GetDependencies: TStrings;
- function GetUnitSource: TStrings;
- procedure SetOutputFileName(AValue: String);
- procedure SetUnitName(AValue: string);
- Protected
- bIsCustomAutomatable,bIsInterface,bIsAutomatable,bIsExternalDecl,bIsUserDefined:boolean;
- // Construct unit from header, uses, interface,
- procedure BuildUnit; virtual;
- // Add to various parts of sources
- Procedure AddToUses(Const AUnit : String); virtual;
- Procedure AddToHeader(Const ALine : String; AllowDuplicate : Boolean = False);virtual;
- Procedure AddToHeader(Const Fmt : String; Args : Array of const; AllowDuplicate : Boolean = False);
- Procedure AddToInterface(Const ALine : String);virtual;
- Procedure AddToInterface(Const Fmt : String; Args : Array of const);
- Procedure AddToImplementation(Const ALine : String);virtual;
- Procedure AddToImplementation(Const Fmt : String; Args : Array of const);
- // utility functions
- function interfacedeclaration(iName, iDoc: string; TI: ITypeInfo; TA: LPTYPEATTR;
- bIsDispatch,bCreateEvents:boolean): string;
- function VarTypeIsAutomatable(ParamType: integer): boolean; virtual;
- function VarTypeToStr(ParamType: integer): string; virtual;
- function TypeToString(TI: ITypeInfo; TD: TYPEDESC): string; virtual;
- function ValidateID(id: string): boolean; virtual;
- // The actual routines that do the work.
- procedure CreateCoClasses(const TL: ITypeLib; TICount: Integer); virtual;
- procedure CreateForwards(const TL: ITypeLib; TICount: Integer); virtual;
- procedure CreateInterfaces(const TL: ITypeLib; TICount: Integer); virtual;
- procedure CreateRecordsUnionsAliases(const TL: ITypeLib; TICount: Integer); virtual;
- procedure CreateUnitHeader(const TL: ITypeLib; const LA: lpTLIBATTR); virtual;
- procedure ImportEnums(const TL: ITypeLib; TICount: Integer); virtual;
- procedure ImportGUIDs(const TL: ITypeLib; TICount: Integer); virtual;
- Procedure DoImportTypelib;virtual;
- // For the benefit of descendents;
- Property UsesClause : TStrings read FUses;
- Property Header : TStrings read FHeader;
- Property InterfaceSection : TStrings Read FInterface;
- Property ImplementationSection : TStrings Read FImplementation;
- Public
- Constructor Create(AOwner : TComponent); override;
- Destructor Destroy; override;
- Procedure Execute;
- Property Dependencies : TStrings Read GetDependencies;
- Property UnitSource : TStrings Read GetUnitSource;
- Published
- // Create ActiveXContainer descendant: default false
- Property ActiveX : Boolean Read FActiveX write FActiveX Default False;
- // Append version number to unit name.
- Property AppendVersionNumber : Boolean Read FAppendVersionNumber Write FAppendVersionNumber Default True;
- // File to read typelib from.
- Property InputFileName : WideString Read FInputFileName Write FInputFileName;
- // If set, unit source will be written to this file.
- Property OutputFileName : String Read FOutputFileName Write SetOutputFileName;
- // Set automatically by OutputFileName or by Execute
- Property UnitName : string Read FUnitname Write SetUnitName;
- end;
- implementation
- Resourcestring
- SErrInvalidUnitName = 'Invalid unit name : %s';
- function ImportTypelib(FileName: WideString;var sUnitName:string;var slDependencies:TStringList;
- bActiveX:boolean):string;
- var i:integer;
- begin
- With TTypeLibImporter.Create(Nil) do
- try
- InputFileName:=FileName;
- ActiveX:=bActiveX;
- Execute;
- Result:=UnitSource.Text;
- sUnitname:=UnitName+'.pas';
- if Assigned(slDependencies) then
- begin //add new dependencies
- for i:=0 to Dependencies.Count-1 do
- if slDependencies.IndexOf(Dependencies[i])=-1 then
- slDependencies.Add(Dependencies[i]);
- end;
- finally
- Free;
- end;
- end;
- function TTypeLibImporter.VarTypeIsAutomatable(ParamType:integer): boolean;
- begin
- result:=ParamType in [vt_i1,vt_ui1,vt_i2,vt_ui2,vt_i4,vt_ui4,vt_uint,
- vt_i8,VT_UI8,vt_bool,vt_r4,vt_r8,vt_cy,vt_date,
- VT_BSTR,VT_VARIANT,VT_DISPATCH,VT_UNKNOWN,vt_hresult,VT_INT,
- VT_LPWSTR,VT_LPSTR];
- end;
- function TTypeLibImporter.VarTypeToStr(ParamType:integer): string;
- begin
- case ParamType of
- vt_empty : Result := 'Empty';
- vt_null : Result := 'Null';
- vt_i2 : Result := 'Smallint';
- vt_i4 : Result := 'Integer';
- vt_r4 : Result := 'Single';
- vt_r8 : Result := 'Double';
- vt_cy : Result := 'Currency';
- vt_date : Result := 'TDateTime';
- vt_bstr : Result := 'WideString';
- vt_dispatch : Result := 'IDispatch';
- vt_error : Result := 'SCODE';
- vt_bool : Result := 'WordBool';
- vt_variant : Result := 'Variant';
- vt_unknown : Result := 'IUnknown';
- vt_i1 : Result := 'ShortInt';
- vt_ui1 : Result := 'Byte';
- vt_ui2 : Result := 'Word';
- vt_ui4 : Result := 'LongWord';
- vt_i8 : Result := 'Int64';
- VT_UI8: Result := 'QWord';
- vt_clsid : Result := 'TGUID';
- vt_void : Result := 'pointer';
- vt_ptr : Result := 'Pointer';
- vt_uint : Result := 'UInt';
- vt_userdefined : Result := 'User defined';
- vt_hresult : Result := 'HResult';
- VT_INT:Result:='SYSINT';
- VT_SAFEARRAY:Result:='PSafeArray';
- VT_LPWSTR:Result:='PWideChar';
- VT_LPSTR:Result:='PChar';
- else
- Result := 'Unknown (' + IntToStr(ParamType) + ')';
- end;
- end;
- function TTypeLibImporter.ValidateID(id:string):boolean;
- const
- RESERVEDCNT=111;
- RESERVED:array[1..RESERVEDCNT] of string=
- ('absolute','and','array','asm','begin','break','case','const',
- 'constructor','continue','destructor','div','do','downto','else','end',
- 'file','for','function','goto','if','implementation','in','inherited',
- 'inline','interface','label','mod','nil','not','object','of',
- 'on','operator','or','packed','procedure','program','record','reintroduce',
- 'repeat','self','set','shl','shr','string','then','to',
- 'type','unit','until','uses','var','while','with','xor',
- 'as','class','except','exports','finalization','finally','initialization',
- 'is','library','on','property','raise','threadvar','try',
- 'dispose','exit','false','new','true',
- 'abs','arctan','boolean','char','cos','dispose','eof','eoln',
- 'exp','false','input','integer','ln','maxint','new','odd',
- 'ord','output','pack','page','pred','read','readln','real',
- 'reset','rewrite','round','sin','sqr','sqrt','succ','text',
- 'true','trunc','write','writeln');
- var
- sl:string;
- i:integer;
- begin
- sl:=lowercase(id);
- result:=true;
- for i:=1 to RESERVEDCNT do
- if sl= RESERVED[i] then
- begin
- result:=false;
- break;
- end;
- end;
- function TTypeLibImporter.TypeToString(TI:ITypeInfo; TD:TYPEDESC):string;
- var
- TIref: ITypeInfo;
- TARef:LPTYPEATTR;
- TLRef: ITypeLib;
- LARef: lpTLIBATTR;
- BstrName : WideString;
- il:LongWord;
- i,idims:integer;
- sl,sRefSrc,sKey:string;
- Handle:HKEY;
- bWasPointer:boolean;
- begin
- result:='';
- bIsCustomAutomatable:=false;
- bIsInterface:=false;
- bIsExternalDecl:=false;
- bIsUserDefined:=false;
- if (TD.vt=vt_userdefined) or ((TD.vt=VT_PTR) and (TD.lptdesc^.vt=vt_userdefined)) then
- begin
- // interface references are dealt with now because they are pointers in fpc.
- // Recursive algorithm makes it difficult to remove a single preceding 'P' from the result.
- bIsUserDefined:=true;
- bWasPointer:=(TD.vt=VT_PTR);
- if bWasPointer then
- TD:=TD.lptdesc^;
- OleCheck(TI.GetRefTypeInfo(TD.hreftype,TIref));
- OleCheck(TIRef.GetDocumentation(DISPID_UNKNOWN, @BstrName, nil, nil, nil));
- result:=BstrName;
- OleCheck(TIRef.GetTypeAttr(TARef));
- bIsCustomAutomatable:=TARef^.typekind in [TKIND_DISPATCH,TKIND_INTERFACE,TKIND_ENUM];
- if TARef^.typekind=TKIND_ALIAS then
- begin
- TypeToString(TIRef,TARef^.tdescAlias); //not interested in result, only bIsCustomAutomatable and bIsInterface
- bIsCustomAutomatable:=bIsAutomatable;
- end
- else
- bIsInterface:=TARef^.typekind in [TKIND_DISPATCH,TKIND_INTERFACE] ;
- if bWasPointer and not bIsInterface then // interfaces are pointers to interface in fpc
- result:='P'+result;
- OleCheck(TIRef.GetContainingTypeLib(TLRef,il));
- OleCheck(TLRef.GetDocumentation(-1, @BstrName, nil, nil, nil));
- OleCheck(TLRef.GetLibAttr(LARef));
- if FAppendVersionNumber then
- sl:=format('%s_%d_%d_TLB',[BstrName,LARef^.wMajorVerNum,LARef^.wMinorVerNum])
- else
- sl:=format('%s_TLB',[BstrName]);
- if (LowerCase(BstrName)='stdole') then // don't include, uses pre-defined stdole2.pas if V2
- begin
- bIsExternalDecl:=true;
- if lowercase(result)='guid' then
- result:='TGUID';
- if (LARef^.wMajorVerNum=2) and (FUses.IndexOf('stdole2')=-1) then
- begin
- AddToHeader('// Dependency: stdole v2 (stdole2.pas)');
- FUses.Add('stdole2');
- end;
- end
- else if (LowerCase(sl)<>LowerCase(UnitName)) and (FUses.IndexOf(sl)=-1) then
- begin // add dependency
- // find source in registry key HKEY_CLASSES_ROOT\TypeLib\GUID\version\0\win32
- bIsExternalDecl:=true;
- il:=MAX_PATH;
- SetLength(sRefSrc,il);
- sKey:=format('\TypeLib\%s\%d.%d\0\win32',[GUIDToString(LARef^.GUID),LARef^.wMajorVerNum,LARef^.wMinorVerNum]);
- if (RegOpenKeyEx(HKEY_CLASSES_ROOT,pchar(sKey),0,KEY_READ,Handle) = ERROR_SUCCESS) then
- begin
- if RegQueryValue(Handle,nil,@sRefSrc[1],@il) = ERROR_SUCCESS then
- begin
- SetLength(sRefSrc,il-1); // includes null terminator
- if not FDependencies.Find(sRefSrc,i) then
- FDependencies.Add(sRefSrc);
- end
- else
- sRefSrc:=GUIDToString(LARef^.GUID);
- RegCloseKey(Handle);
- end;
- AddToHeader('// Dependency: %s v%d.%d (%s)',[BstrName,LARef^.wMajorVerNum,LARef^.wMinorVerNum,sRefSrc]);
- FUses.Add(sl);
- TLRef.ReleaseTLibAttr(LARef);
- end;
- TIRef.ReleaseTypeAttr(TARef);
- end
- else if TD.vt=VT_PTR then //pointer type
- begin
- TD:=TD.lptdesc^;
- result:='P'+TypeToString(TI,TD);
- bIsAutomatable:=(VarTypeIsAutomatable(TD.vt) {and (TD.vt<>VT_VARIANT)}) or bIsCustomAutomatable;
- exit;
- end
- else if TD.vt=VT_CARRAY then //C type array
- begin
- // get array element type
- sl:=TypeToString(TI,TD.lpadesc^.tdescElem);
- // get dimensions
- idims:=TD.lpadesc^.cDims;
- result:='array[';
- // get boundaries for every dimension
- for i:=0 to idims-1 do
- result:=result+IntToStr(TD.lpadesc^.rgbounds[i].lLbound)+'..'+IntToStr(TD.lpadesc^.rgbounds[i].cElements - TD.lpadesc^.rgbounds[i].lLbound -1)+',';
- result[length(result)]:=']';
- result:=result + ' of '+sl;
- end
- else
- result:=VarTypeToStr(TD.vt);
- bIsAutomatable:=VarTypeIsAutomatable(TD.vt) or bIsCustomAutomatable;
- end;
- function TTypeLibImporter.interfacedeclaration(iName,iDoc:string;TI:ITypeInfo;TA:LPTYPEATTR;
- bIsDispatch,bCreateEvents:boolean):string;
- type
- TPropertyDef=record
- idispid:integer;
- bput,bget:boolean;
- iptype,igtype:integer;
- name,
- sptype, // only used if iptype=igtype
- sorgname,
- sdoc,
- sParam,
- sDefault:string;
- end;
- var
- RTIT: HREFTYPE;
- TIref: ITypeInfo;
- BstrName,BstrNameRef,BstrDocString : WideString;
- s,sl,sPropIntfc,sPropDispIntfc,sType,sConv,sFunc,sPar,sVarName,sMethodName,sPropParam,sPropParam2:string;
- sEventSignatures,sEventFunctions,sEventProperties,sEventImplementations:string;
- i,j,k:integer;
- FD: lpFUNCDESC;
- BL : array[0..99] of TBstr;
- cnt:LongWord;
- TD: TYPEDESC;
- bPropHasParam,bIsFunction,bParamByRef:boolean;
- VD: lpVARDESC;
- aPropertyDefs:array of TPropertyDef;
- Propertycnt,iType:integer;
- function findProperty(ireqdispid:integer):integer;
- var i:integer;
- begin
- for i:=0 to Propertycnt-1 do
- if aPropertyDefs[i].idispid=ireqdispid then
- begin
- result:=i;
- exit;
- end;
- result:=Propertycnt;
- Propertycnt:=Propertycnt+1;
- with aPropertyDefs[result] do
- begin
- idispid:=ireqdispid;
- bput:=false;
- bget:=false;
- name:='';
- iptype:=vt_empty;
- igtype:=vt_empty;
- sptype:='';
- sorgname:='';
- sdoc:='';
- sParam:='';
- sDefault:='';
- end;
- end;
- begin
- Propertycnt:=0;
- SetLength(aPropertyDefs,TA^.cFuncs+TA^.cVars); // worst case, all functions getters or all setters
- sEventSignatures:='';
- sEventFunctions:='';
- sEventProperties:='';
- sEventImplementations:='';
- if not bIsDispatch then
- begin
- // find base class
- if TA^.cImplTypes>0 then
- begin
- OleCheck(TI.GetRefTypeOfImplType(0,RTIT));
- OleCheck(TI.GetRefTypeInfo(RTIT,TIref));
- OleCheck(TIRef.GetDocumentation(DISPID_UNKNOWN, @BstrNameRef, nil, nil, nil));
- s:=format(#13#10'// %s : %s'#13#10#13#10' %s = interface(%s)'#13#10,[iname,iDoc,iname,BstrNameRef]);
- end
- else // no base class
- begin
- s:=format(#13#10'// %s : %s'#13#10#13#10' %s = interface'#13#10,[iname,iDoc,iname]);
- end;
- end
- else
- if (TA^.wTypeFlags and TYPEFLAG_FDUAL)=TYPEFLAG_FDUAL then
- s:=format(#13#10'// %s : %s'#13#10#13#10' %sDisp = dispinterface'#13#10,[iname,iDoc,iname])
- else
- s:=format(#13#10'// %s : %s'#13#10#13#10' %s = dispinterface'#13#10,[iname,iDoc,iname]);
- sPropIntfc:='';
- sPropDispIntfc:='';
- s:=s+format(' [''%s'']'#13#10,[GUIDToString(TA^.GUID)]);
- for j:=0 to TA^.cFuncs-1 do
- begin
- OleCheck(TI.GetFuncDesc(j,FD));
- OleCheck(TI.GetNames(FD^.memid,@BL,length(BL),cnt));
- // skip IUnknown and IDispatch methods
- sl:=lowercase(BL[0]);
- if (sl='queryinterface') or (sl='addref') or (sl='release') then //IUnknown
- continue;
- if bIsDispatch and
- ((sl='gettypeinfocount') or (sl='gettypeinfo') or (sl='getidsofnames') or (sl='invoke')) then //IDispatch
- continue;
- // get return type
- if bIsDispatch and ((FD^.invkind=INVOKE_PROPERTYGET) or (FD^.invkind=INVOKE_FUNC)) then
- begin
- sType:=TypeToString(TI,FD^.elemdescFunc.tdesc);
- iType:=FD^.elemdescFunc.tdesc.vt;
- end
- else
- if FD^.cParams>0 then
- begin
- sType:=TypeToString(TI,FD^.lprgelemdescParam[FD^.cParams-1].tdesc);
- iType:=FD^.lprgelemdescParam[FD^.cParams-1].tdesc.vt;
- if ((FD^.lprgelemdescParam[FD^.cParams-1].paramdesc.wParamFlags and (PARAMFLAG_FRETVAL or PARAMFLAG_FOUT)) <>0) then
- begin
- delete(sType,1,1); //out parameters are always defined as pointer
- if assigned(FD^.lprgelemdescParam[FD^.cParams-1].tdesc.lptdesc) then
- iType:=FD^.lprgelemdescParam[FD^.cParams-1].tdesc.lptdesc^.vt;
- end;
- end;
- //get calling convention
- if FD^.callconv=CC_STDCALL then
- begin
- if lowercase(BstrNameRef)='iunknown' then
- sConv:='stdcall'
- else
- sConv:='safecall';
- end
- else
- sConv:='cdecl';
- // get info
- OleCheck(TI.GetDocumentation(FD^.memid, @BstrName, @BstrDocString, nil, nil));
- case FD^.invkind of
- // build function/procedure
- INVOKE_FUNC :
- begin
- if ValidateID(BstrName) then
- sMethodName:=BstrName
- else
- begin
- sMethodName:=BstrName+'_';
- AddToHeader('// Warning: renamed method ''%s'' in %s to ''%s''',[BstrName,iname,sMethodName],True);
- end;
- bIsFunction:=(bIsDispatch and (FD^.elemdescFunc.tdesc.vt<>VT_VOID)) or
- (not bIsDispatch and (FD^.cParams>0) and ((FD^.lprgelemdescParam[FD^.cParams-1].paramdesc.wParamFlags and PARAMFLAG_FRETVAL ) <>0));
- if bIsFunction then
- sFunc:=format(' // %s : %s '#13#10' function %s(',[sMethodName,BstrDocString,sMethodName])
- else
- sFunc:=format(' // %s : %s '#13#10' procedure %s(',[sMethodName,BstrDocString,sMethodName]);
- if bIsFunction and bIsDispatch and not bIsAutomatable then
- begin
- AddToHeader('// Warning: ''%s'' not automatable in %sdisp.%s',[stype,iname,BstrName],True);
- sType:='{!! '+sType+' !!} OleVariant';
- end;
- if bCreateEvents then
- begin
- sEventSignatures:=sEventSignatures+format(' T%s%s = procedure(Sender: TObject;',[iname,sMethodName]);
- sEventFunctions:=sEventFunctions+format(' FOn%s:T%s%s;'#13#10,[sMethodName,iname,sMethodName]);
- sEventProperties:=sEventProperties+format(' property On%s : T%s%s read FOn%s write FOn%s;'#13#10,
- [sMethodName,iname,sMethodName,sMethodName,sMethodName]);
- sEventImplementations:=sEventImplementations+
- format(' %d: if assigned(On%s) then'#13#10+
- ' On%s(Self,',[FD^.memid,sMethodName,sMethodName]);
- end;
- // parameters
- for k:=0 to FD^.cParams-1 do
- begin
- bParamByRef:=(FD^.lprgelemdescParam[k].tdesc.vt=VT_PTR) and // by ref
- not((FD^.lprgelemdescParam[k].tdesc.lptdesc^.vt=VT_USERDEFINED) and bIsInterface);// but not pointer to interface
- if (FD^.lprgelemdescParam[k].paramdesc.wParamFlags and PARAMFLAG_FRETVAL ) <>0 then //return type
- continue;
- sl:=TypeToString(TI,FD^.lprgelemdescParam[k].tdesc);
- if bParamByRef then
- delete(sl,1,1);
- if bIsDispatch and not bIsAutomatable then
- begin
- AddToHeader('// Warning: ''%s'' not automatable in %sdisp.%s',[sl,iname,sMethodName],True);
- sl:='{!! '+sl+' !!} OleVariant';
- end;
- sPar:='';
- if bParamByRef then
- case FD^.lprgelemdescParam[k].paramdesc.wParamFlags and (PARAMFLAG_FIN or PARAMFLAG_FOUT) of
- PARAMFLAG_FIN or PARAMFLAG_FOUT:sPar:='var ';
- PARAMFLAG_FOUT:sPar:='out ';
- PARAMFLAG_FIN:sPar:='var '; //constref in safecall? TBD
- end;
- if ValidateID(BL[k+1]) then
- sVarName:=BL[k+1]
- else
- begin
- sVarName:=BL[k+1]+'_';
- AddToHeader('// Warning: renamed parameter ''%s'' in %s.%s to ''%s'''#13#10,[BL[k+1],iname,sMethodName,sVarName],True);
- end;
- sPar:=sPar+format('%s:%s;',[sVarName,sl]);
- sFunc:=sFunc+sPar;
- if bCreateEvents then
- begin
- sEventSignatures:=sEventSignatures+sPar;
- //params are numbered last to first
- if bParamByRef and not(bIsDispatch and not bIsAutomatable) then
- begin
- case FD^.lprgelemdescParam[k].tdesc.lptdesc^.vt of
- VT_UI1: sl:='pbVal';
- VT_UI2: sl:='puiVal';
- VT_UI4: sl:='pulVal';
- VT_UI8: sl:='pullVal';
- VT_I1: sl:='pcVal';
- VT_I2: sl:='piVal';
- VT_I4: sl:='plVal';
- VT_I8: sl:='pllVal';
- VT_R4: sl:='pfltVal';
- VT_R8: sl:='pdblVal';
- VT_BOOL: sl:='pbool';
- VT_ERROR: sl:='pscode';
- VT_CY: sl:='pcyVal';
- VT_DATE: sl:='pdate';
- VT_BSTR: sl:='pbstrVal';
- VT_UNKNOWN: sl:='punkVal';
- VT_DISPATCH: sl:='pdispVal';
- VT_ARRAY: sl:='pparray';
- VT_VARIANT: sl:='pvarVal';
- end;
- sEventImplementations:=sEventImplementations+format(' Params.rgvarg[%d].%s^,',[FD^.cParams-1-k,sl]);
- end
- else
- sEventImplementations:=sEventImplementations+format(' OleVariant(Params.rgvarg[%d]),',[FD^.cParams-1-k]);
- end;
- end;
- // finish interface and dispinterface
- if sFunc[length(sFunc)]=';' then
- sFunc[length(sFunc)]:=')'
- else // no params
- delete(sFunc,length(sFunc),1);
- if bCreateEvents then
- begin
- sEventSignatures[length(sEventSignatures)]:=')';
- sEventSignatures:=sEventSignatures+' of object;'#13#10;
- sEventImplementations[length(sEventImplementations)]:=')';
- sEventImplementations:=sEventImplementations+';'#13#10;
- end;
- if bIsFunction then
- sFunc:=sFunc+format(':%s',[sType]);
- if bIsDispatch then
- s:=s+sFunc+format(';dispid %d;'#13#10,[FD^.memid])
- else
- s:=s+sFunc+format(';%s;'#13#10,[sConv]);
- end;
- INVOKE_PROPERTYGET,INVOKE_PROPERTYPUT,INVOKE_PROPERTYPUTREF :
- // build properties. Use separate string to group properties at end of interface declaration.
- begin
- if ValidateID(BstrName) then
- sMethodName:=BstrName
- else
- begin
- sMethodName:=BstrName+'_';
- AddToHeader('// Warning: renamed property ''%s'' in %s to ''%s''',[BstrName,iname,sMethodName]);
- end;
- bPropHasParam:=(((FD^.invkind=INVOKE_PROPERTYGET) and (FD^.cParams>0)) or (FD^.cParams>1))
- and ((FD^.lprgelemdescParam[0].paramdesc.wParamFlags and PARAMFLAG_FIN) = PARAMFLAG_FIN) ;
- if (FD^.memid=0) and bPropHasParam then sl:=' default;' else sl:='';
- sPropParam:='';
- sPropParam2:='';
- if bPropHasParam then
- begin
- sPropParam:=BL[1]+':'+TypeToString(TI,FD^.lprgelemdescParam[0].tdesc);
- end;
- if bIsDispatch then
- begin
- if (TD.vt<>VT_VOID) and not bIsAutomatable then
- begin
- AddToHeader('// Warning: ''%s'' not automatable in %s.%s',[stype,iname,BstrName]);
- sType:='{!! '+sType+' !!} OleVariant';
- end;
- if bPropHasParam then
- sPropParam:='['+sPropParam+']';
- i:=pos(format('dispid %d;',[FD^.memid]),sPropDispIntfc);
- if i<=0 then
- begin
- if FD^.invkind=INVOKE_PROPERTYGET then
- sType:=sType+' readonly '
- else
- sType:=sType+' writeonly';
- sPropDispIntfc:=sPropDispIntfc+format(' // %s : %s '#13#10' property %s%s:%s dispid %d;%s'#13#10,
- [BstrName,BstrDocString,sMethodName,sPropParam,sType,FD^.memid,sl]);
- end
- else //remove readonly or writeonly
- delete(sPropDispIntfc,i-11,10); //10= length(' readonly ')
- end
- else
- begin
- //getters/setters for interface, insert in interface as they come,
- //store in aPropertyDefs to create properties at the end
- if bPropHasParam then
- begin
- sPropParam2:='('+sPropParam+')';
- sPropParam:='['+sPropParam+']';
- end;
- if FD^.invkind=INVOKE_PROPERTYGET then
- begin
- s:=s+format(' function Get_%s%s : %s; %s;'#13#10,[sMethodName,sPropParam2,sType,sConv]);
- with aPropertyDefs[findProperty(FD^.memid)] do
- begin
- bget:=true;
- name:=sMethodName;
- igtype:=itype;
- sptype:=sType;
- sorgname:=BstrName;
- sdoc:=BstrDocString;
- sParam:=sPropParam;
- sDefault:=sl;
- end;
- end
- else
- begin
- if ValidateID(BL[1]) then
- sVarName:=BL[1]
- else
- begin
- sVarName:=BL[1]+'_';
- AddToHeader('// Warning: renamed parameter ''%s'' in %s.Set_%s to ''%s''',[BL[1],iname,sMethodName,sVarName]);
- end;
- s:=s+format(' procedure Set_%s(const %s:%s); %s;'#13#10,[sMethodName,sVarName,sType,sConv]);
- with aPropertyDefs[findProperty(FD^.memid)] do
- begin
- bput:=true;
- name:=sMethodName;
- iptype:=itype;
- sptype:=sType;
- sorgname:=BstrName;
- sdoc:=BstrDocString;
- sParam:=sPropParam;
- sDefault:=sl;
- end;
- end;
- end;
- end;
- end;
- TI.ReleaseFuncDesc(FD);
- end;
- for j:=0 to TA^.cVars-1 do
- begin //read-write properties only
- if bIsDispatch then
- begin
- TI.GetVarDesc(j,VD);
- if assigned(VD) then
- begin
- TI.GetDocumentation(VD^.memId,@BstrName, @BstrDocString, nil, nil);
- if ValidateID(BstrName) then
- sMethodName:=BstrName
- else
- begin
- sMethodName:=BstrName+'_';
- AddToHeader('// Warning: renamed property ''%s'' in %s to ''%s'''#13#10,[BstrName,iname,sMethodName]);
- end;
- sType:=TypeToString(TI,VD^.ElemdescVar.tdesc);
- sPropDispIntfc:=sPropDispIntfc+format(' // %s : %s '#13#10' property %s:%s dispid %d;'#13#10,
- [BstrName,BstrDocString,sMethodName,sType,VD^.memId]);
- end;
- end;
- end;
- if bCreateEvents then
- begin
- FEventDisp.Add(iname);
- FEventIID.Add(GUIDToString(TA^.GUID));
- FEventSignatures.Add(sEventSignatures);
- FEventFunctions.Add(sEventFunctions);
- FEventProperties.Add(sEventProperties);
- FEventImplementations.Add(sEventImplementations);
- end;
- if bIsDispatch then
- result:=s + sPropDispIntfc +' end;'#13#10
- else
- begin
- // add interface properties
- for i:=0 to Propertycnt-1 do
- with aPropertyDefs[i] do
- if (iptype=igtype) or not bget or not bput then
- begin
- s:=s+format(' // %s : %s '#13#10' property %s%s:%s',[sorgname,sdoc,name,sParam,sptype]);
- if bget then
- s:=s+format(' read Get_%s',[name]);
- if bput then
- s:=s+format(' write Set_%s',[name]);
- s:=s+format(';%s'#13#10,[sDefault]);
- end;
- result:=s+' end;'#13#10;
- end;
- end;
- function TTypeLibImporter.GetDependencies: TStrings;
- begin
- Result:=FDependencies;
- end;
- function TTypeLibImporter.GetUnitSource: TStrings;
- begin
- Result:=FUnitSource;
- end;
- Procedure TTypeLibImporter.ImportGUIDs(Const TL : ITypeLib; TICount : Integer);
- Var
- i : integer;
- BstrName, BstrDocString, BstrHelpFile : WideString;
- dwHelpContext: DWORD;
- TI:ITypeInfo;
- TA:LPTYPEATTR;
- TIT: TYPEKIND;
- begin
- //GUIDs
- for i:=0 to TIcount-1 do
- begin
- OleCheck(TL.GetTypeInfoType(i, TIT));
- OleCheck(TL.GetTypeInfo(i, TI));
- OleCheck(TL.GetDocumentation(i, @BstrName, @BstrDocString, @dwHelpContext, @BstrHelpFile));
- OleCheck(TI.GetTypeAttr(TA));
- case TIT of
- TKIND_DISPATCH,TKIND_INTERFACE:
- begin
- AddToInterface(' IID_%s : TGUID = ''%s'';',[BstrName,GUIDToString(TA^.GUID)]);
- end;
- TKIND_COCLASS:
- begin
- AddToInterface(' CLASS_%s : TGUID = ''%s'';',[BstrName,GUIDToString(TA^.GUID)]);
- end;
- end;
- TI.ReleaseTypeAttr(TA);
- end;
- end;
- Procedure TTypeLibImporter.ImportEnums(Const TL : ITypeLib; TICount : Integer);
- Var
- i,j : integer;
- sl : string;
- BstrName, BstrDocString, BstrHelpFile : WideString;
- dwHelpContext: DWORD;
- TI:ITypeInfo;
- TA:LPTYPEATTR;
- TIT: TYPEKIND;
- bDuplicate:boolean;
- VD: lpVARDESC;
- begin
- //enums
- AddToInterface('');
- AddToInterface('//Enums');
- AddToInterface('');
- for i:=0 to TIcount-1 do
- begin
- OleCheck(TL.GetTypeInfoType(i, TIT));
- OleCheck(TL.GetTypeInfo(i, TI));
- OleCheck(TL.GetDocumentation(i, @BstrName, @BstrDocString, @dwHelpContext, @BstrHelpFile));
- OleCheck(TI.GetTypeAttr(TA));
- if TIT=TKIND_ENUM then
- begin
- bDuplicate:=false;
- if ValidateID(BstrName) then
- sl:=BstrName
- else
- begin
- sl:=BstrName+'_';
- AddToHeader('// Warning: renamed enum type ''%s'' to ''%s''',[BstrName,sl],True);
- end;
- if (InterfaceSection.IndexOf(Format(' %s =TOleEnum;',[sl]))<>-1) then // duplicate enums fe. AXVCL.dll 1.0
- begin
- sl:=sl+IntToStr(i); // index is unique in this typelib
- AddToHeader('// Warning: duplicate enum ''%s''. Renamed to ''%s''. consts appended with %d',[BstrName,sl,i]);
- bDuplicate:=true;
- end;
- AddToInterface('Type');
- AddToInterface(' %s =TOleEnum;',[sl]);
- FTypes.Add(sl);
- AddToInterface('Const');
- for j:=0 to TA^.cVars-1 do
- begin
- TI.GetVarDesc(j,VD);
- if assigned(VD) then
- begin
- TI.GetDocumentation(VD^.memId,@BstrName, nil, nil, nil);
- if ValidateID(BstrName) then
- sl:=BstrName
- else
- begin
- sl:=BstrName+'_';
- AddToHeader('// Warning: renamed enum value ''%s'' to ''%s''',[BstrName,sl],True);
- end;
- if bDuplicate then
- sl:=sl+IntToStr(i);
- if assigned(VD^.lpvarValue) then
- AddToInterface(' %s = $%s;',[sl,IntToHex(PtrInt(VD^.lpvarValue^),16)]);
- end;
- end;
- end;
- TI.ReleaseTypeAttr(TA);
- end;
- end;
- Procedure TTypeLibImporter.CreateForwards(Const TL : ITypeLib; TICount : Integer);
- Var
- i : integer;
- BstrName, BstrDocString, BstrHelpFile : WideString;
- dwHelpContext: DWORD;
- TI:ITypeInfo;
- TA:LPTYPEATTR;
- TIT: TYPEKIND;
- begin
- // Forward declarations
- AddToInterface('//Forward declarations');
- AddToInterface('');
- AddToInterface('Type');
- for i:=0 to TIcount-1 do
- begin
- OleCheck(TL.GetTypeInfoType(i, TIT));
- OleCheck(TL.GetTypeInfo(i, TI));
- OleCheck(TL.GetDocumentation(i, @BstrName, @BstrDocString, @dwHelpContext, @BstrHelpFile));
- OleCheck(TI.GetTypeAttr(TA));
- if (TIT=TKIND_DISPATCH) then
- begin
- if (TA^.wTypeFlags and TYPEFLAG_FDUAL)=TYPEFLAG_FDUAL then
- begin
- AddToInterface(' %s = interface;',[BstrName]);
- AddToInterFace(' %sDisp = dispinterface;',[BstrName]);
- end
- else
- AddToInterface(' %s = dispinterface;',[BstrName]);
- end
- else if (TIT=TKIND_INTERFACE) then
- AddToInterface(' %s = interface;',[BstrName]);
- TI.ReleaseTypeAttr(TA);
- end;
- end;
- Procedure TTypeLibImporter.CreateRecordsUnionsAliases(Const TL : ITypeLib; TICount : Integer);
- Var
- i,j : integer;
- BstrName, BstrDocString, BstrHelpFile : WideString;
- dwHelpContext: DWORD;
- TI:ITypeInfo;
- TA:LPTYPEATTR;
- TIT: TYPEKIND;
- VD: lpVARDESC;
- slDeferredType,slDeferredPendingType,slDeferredDeclaration:TStrings;
- sl,sldeclaration,stype,smembername,srecordname:string;
- bIsDeferred:boolean;
- procedure ReleasePendingType(sPen:string);
- var k:integer;
- sDec,sTyp:string;
- begin
- k:=slDeferredPendingType.IndexOf(sPen);
- while (k>=0) do
- begin
- sDec:=slDeferredDeclaration[k];
- sTyp:=slDeferredType[k];
- slDeferredPendingType.Delete(k);
- slDeferredDeclaration.Delete(k);
- slDeferredType.Delete(k);
- // any other types pending for this declaration ? If yes, wait until all types declared.
- if slDeferredDeclaration.IndexOf(sDec)=-1 then
- begin
- AddToInterface(sDec);
- FTypes.Add(sTyp);
- ReleasePendingType(sTyp);
- end;
- k:=slDeferredPendingType.IndexOf(sPen);
- end;
- end;
- begin
- //records, unions aliases
- AddToInterface('');
- AddToInterface('//records, unions, aliases');
- AddToInterface('');
- slDeferredType:=TStringList.Create;
- slDeferredPendingType:=TStringList.Create;
- slDeferredDeclaration:=TStringList.Create;
- try
- for i:=0 to TIcount-1 do
- begin
- bIsDeferred:=false;
- sldeclaration:='';
- OleCheck(TL.GetTypeInfoType(i, TIT));
- //s:=s+format('type %d'#13#10,[ord(TIT)]);
- OleCheck(TL.GetTypeInfo(i, TI));
- OleCheck(TL.GetDocumentation(i, @BstrName, @BstrDocString, @dwHelpContext, @BstrHelpFile));
- OleCheck(TI.GetTypeAttr(TA));
- case TIT of
- TKIND_RECORD,TKIND_UNION:
- begin
- if ValidateID(BstrName) then
- sRecordName:=BstrName
- else
- begin
- sRecordName:=BstrName+'_';
- AddToHeader('// Warning: renamed record ''%s'' to ''%s''',[BstrName,sRecordName],True);
- end;
- AddToInterface(' P%s = ^%s;'#13#10,[sRecordName,sRecordName]);
- FTypes.Add('P'+sRecordName);
- ReleasePendingType('P'+sRecordName);
- if TIT=TKIND_RECORD then
- sldeclaration:=sldeclaration+format(' %s = packed record'#13#10,[sRecordName])
- else
- begin
- sldeclaration:=sldeclaration+format(' %s = record'#13#10,[sRecordName]);
- sldeclaration:=sldeclaration+' case Integer of'#13#10;
- end;
- for j:=0 to TA^.cVars-1 do
- begin
- TI.GetVarDesc(j,VD);
- TI.GetDocumentation(VD^.memId,@BstrName, @BstrDocString, @dwHelpContext, @BstrHelpFile);
- if ValidateID(BstrName) then
- smemberName:=BstrName
- else
- begin
- smemberName:=BstrName+'_';
- AddToHeader('// Warning: renamed record member ''%s'' in %s to ''%s''',[BstrName,sRecordName,smemberName],True);
- end;
- stype:=TypeToString(TI, VD^.ElemdescVar.tdesc);
- if bIsUserDefined and not ValidateID(stype) then
- stype:=stype+'_';
- if bIsUserDefined and not bIsExternalDecl and (FTypes.IndexOf(stype)=-1) then //not defined yet, defer
- begin
- bIsDeferred:=true;
- slDeferredPendingType.Add(stype);
- slDeferredType.Add(sRecordName);
- end;
- if TIT=TKIND_RECORD then
- sldeclaration:=sldeclaration+format(' %s : %s;'#13#10,[smemberName,stype])
- else
- sldeclaration:=sldeclaration+format(' %d: (%s : %s);'#13#10,[j,smemberName,stype]);
- end;
- sldeclaration:=sldeclaration+' end;';
- if not bIsDeferred then
- begin
- AddToInterface(sldeclaration);
- FTypes.Add(sRecordName);
- ReleasePendingType(sRecordName);
- end
- else
- for j:=slDeferredDeclaration.Count to slDeferredType.Count-1 do // catch up on slDeferredType
- slDeferredDeclaration.Add(sldeclaration);
- end;
- TKIND_ALIAS:
- begin
- stype:=TypeToString(TI, TA^.tdescAlias);
- if bIsUserDefined and not ValidateID(stype) then
- stype:=stype+'_';
- if ValidateID(BstrName) then
- sRecordName:=BstrName
- else
- begin
- sRecordName:=BstrName+'_';
- AddToHeader('// Warning: renamed alias ''%s'' to ''%s''',[BstrName,sRecordName],True);
- end;
- sl:=format(' %s = %s;',[sRecordName,stype]);
- if bIsUserDefined and not bIsExternalDecl and (FTypes.IndexOf(stype)=-1) then //not defined yet, defer
- begin
- slDeferredDeclaration.Add(sl);
- slDeferredPendingType.Add(stype);
- slDeferredType.Add(sRecordName);
- end
- else
- begin
- AddToInterface(sl);
- FTypes.Add(sRecordName);
- ReleasePendingType(sRecordName);
- end;
- end;
- end;
- TI.ReleaseTypeAttr(TA);
- end;
- if slDeferredDeclaration.Count>1 then // circular references
- begin
- AddToHeader('// Error : the following type declarations have circular references',True);
- AddToInterface('// circular references start here');
- for j:=0 to slDeferredDeclaration.Count-1 do
- AddToHeader('// %s',[slDeferredType[j]]);
- for j:=0 to slDeferredDeclaration.Count-1 do
- AddToInterface(slDeferredDeclaration[j]);
- end;
- finally
- slDeferredDeclaration.Free;
- slDeferredPendingType.Free;
- slDeferredType.Free;
- end;
- end;
- Procedure TTypeLibImporter.CreateInterfaces(Const TL : ITypeLib; TICount : Integer);
- Var
- i : integer;
- BstrName, BstrDocString, BstrHelpFile : WideString;
- dwHelpContext : DWORD;
- TI,TIref : ITypeInfo;
- TA,TAref : LPTYPEATTR;
- TIT : TYPEKIND;
- RTIT : HREFTYPE;
- begin
- // interface declarations
- AddToInterface('//interface declarations');
- for i:=0 to TIcount-1 do
- begin
- OleCheck(TL.GetTypeInfoType(i, TIT));
- OleCheck(TL.GetTypeInfo(i, TI));
- OleCheck(TL.GetDocumentation(i, @BstrName, @BstrDocString, @dwHelpContext, @BstrHelpFile));
- if (TIT=TKIND_DISPATCH) or (TIT=TKIND_INTERFACE) then
- begin
- OleCheck(TI.GetTypeAttr(TA));
- if (TIT=TKIND_DISPATCH) then
- begin
- // get also TKIND_INTERFACE if dual interface
- if (TA^.wTypeFlags and TYPEFLAG_FDUAL)=TYPEFLAG_FDUAL then
- begin
- OleCheck(TI.GetRefTypeOfImplType(-1,RTIT));
- OleCheck(TI.GetRefTypeInfo(RTIT,TIref));
- OleCheck(TIref.GetTypeAttr(TAref));
- AddToInterface(interfacedeclaration(BstrName,BstrDocString,TIref,TAref,false,false));
- TIref.ReleaseTypeAttr(TAref);
- AddToInterface(interfacedeclaration(BstrName,BstrDocString,TI,TA,true,false));
- end
- else
- AddToInterface(interfacedeclaration(BstrName,BstrDocString,TI,TA,true,true));
- end
- else
- AddToInterface(interfacedeclaration(BstrName,BstrDocString,TI,TA,false,false));
- TI.ReleaseTypeAttr(TA);
- end;
- end;
- end;
- Procedure TTypeLibImporter.CreateCoClasses(Const TL : ITypeLib; TICount : Integer);
- Var
- i, j ,idx: integer;
- BstrName, BstrDocString, BstrHelpFile, BstrNameRef : WideString;
- dwHelpContext : DWORD;
- TI,TIref : ITypeInfo;
- TA : LPTYPEATTR;
- TIT : TYPEKIND;
- RTIT : HREFTYPE;
- sDefIntf, sDefEvents : string;
- ITF:WINT;
- begin
- //CoClasses
- AddToInterface('//CoClasses');
- AddToImplementation('implementation');
- AddToImplementation('');
- AddToImplementation('uses comobj;');
- AddToImplementation('');
- for i:=0 to TIcount-1 do
- begin
- OleCheck(TL.GetTypeInfoType(i, TIT));
- if TIT =TKIND_COCLASS then
- begin
- OleCheck(TL.GetTypeInfo(i, TI));
- OleCheck(TL.GetDocumentation(i, @BstrName, @BstrDocString, @dwHelpContext, @BstrHelpFile));
- OleCheck(TI.GetTypeAttr(TA));
- // get default interface and events.
- sDefEvents:='';
- for j:=0 to TA^.cImplTypes-1 do
- begin
- OleCheck(TI.GetImplTypeFlags(J,ITF));
- if (ITF and IMPLTYPEFLAG_FDEFAULT)<>0 then
- begin
- OleCheck(TI.GetRefTypeOfImplType(J,RTIT));
- OleCheck(TI.GetRefTypeInfo(RTIT,TIref));
- OleCheck(TIRef.GetDocumentation(DISPID_UNKNOWN, @BstrNameRef, nil, nil, nil));
- if (ITF and IMPLTYPEFLAG_FSOURCE)<>0 then
- begin
- sDefEvents:=BstrNameRef;
- idx:=FEventDisp.IndexOf(sDefEvents);
- if idx<0 then // should not happen
- sDefEvents:='';
- end
- else
- sDefIntf:=BstrNameRef;
- end;
- end;
- if sDefEvents<>'' then //add event signatures
- begin
- AddToInterface(FEventSignatures[idx]);
- FEventSignatures[idx]:=''; // only add event signatures only once. Multiple coclasses can use same events
- AddToInterface('');
- end;
- AddToInterFace(' Co%s = Class',[BstrName]);
- AddToInterface(' Public');
- AddToInterface(' Class Function Create: %s;',[sDefIntf]);
- AddToInterFace(' Class Function CreateRemote(const MachineName: string): %s;',[sDefIntf]);
- AddToInterFace(' end;');
- AddToInterFace('');
- if FActiveX then
- begin
- if FUses.IndexOf('ActiveXContainer')<0 then
- FUses.Add('ActiveXContainer');
- AddToInterFace(' T%s = Class(TActiveXContainer)',[BstrName]);
- AddToInterface(' Private');
- AddToInterface(' FServer:%s;',[sDefIntf]);
- if (sDefEvents<>'') then //add function variables
- begin
- if FUses.IndexOf('Eventsink')<0 then
- FUses.Add('EventSink');
- AddToInterface(FEventFunctions[idx]);
- AddToInterface(' FEventSink:TEventSink;',[sDefIntf]);
- AddToInterface(' procedure EventSinkInvoke(Sender: TObject; DispID: Integer;');
- AddToInterface(' const IID: TGUID; LocaleID: Integer; Flags: Word;');
- AddToInterface(' Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer);');
- end;
- AddToInterface(' Public');
- AddToInterface(' constructor Create(TheOwner: TComponent); override;');
- AddToInterface(' destructor Destroy; override;');
- AddToInterface(' property OleServer:%s read FServer;',[sDefIntf]);
- AddToInterFace(' Published');
- AddToInterFace(' property Align;');
- AddToInterFace(' property Anchors;');
- AddToInterFace(' property AutoSize;');
- AddToInterFace(' property BorderSpacing;');
- AddToInterFace(' property ChildSizing;');
- AddToInterFace(' property ClientHeight;');
- AddToInterFace(' property ClientWidth;');
- AddToInterFace(' property Constraints;');
- AddToInterFace(' property DockSite;');
- AddToInterFace(' property DragCursor;');
- AddToInterFace(' property DragKind;');
- AddToInterFace(' property DragMode;');
- AddToInterFace(' property Enabled;');
- AddToInterFace(' property ParentShowHint;');
- AddToInterFace(' property PopupMenu;');
- AddToInterFace(' property ShowHint;');
- AddToInterFace(' property TabOrder;');
- AddToInterFace(' property TabStop;');
- AddToInterFace(' property UseDockManager default True;');
- AddToInterFace(' property Visible;');
- AddToInterFace(' property OnContextPopup;');
- AddToInterFace(' property OnDockDrop;');
- AddToInterFace(' property OnDockOver;');
- AddToInterFace(' property OnDragDrop;');
- AddToInterFace(' property OnDragOver;');
- AddToInterFace(' property OnEndDock;');
- AddToInterFace(' property OnEndDrag;');
- AddToInterFace(' property OnEnter;');
- AddToInterFace(' property OnExit;');
- AddToInterFace(' property OnGetSiteInfo;');
- AddToInterFace(' property OnGetDockCaption;');
- AddToInterFace(' property OnResize;');
- AddToInterFace(' property OnStartDock;');
- AddToInterFace(' property OnStartDrag;');
- AddToInterFace(' property OnStatusText;');
- AddToInterFace(' property OnUnDock;');
- if (sDefEvents<>'') then
- AddToInterface(FEventProperties[idx]);
- AddToInterFace(' property Active;');
- AddToInterFace(' end;');
- AddToInterFace('');
- end
- else if (sDefEvents<>'') then //add function variables
- begin
- if FUses.IndexOf('Eventsink')<0 then
- FUses.Add('EventSink');
- AddToInterFace(' T%s = Class(TEventSink)',[BstrName]);
- AddToInterface(' Private');
- AddToInterface(FEventFunctions[idx]);
- AddToInterface(' fServer:%s;',[sDefIntf]);
- AddToInterface(' procedure EventSinkInvoke(Sender: TObject; DispID: Integer;');
- AddToInterface(' const IID: TGUID; LocaleID: Integer; Flags: Word;');
- AddToInterface(' Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer);');
- AddToInterface(' Public');
- AddToInterface(' constructor Create(TheOwner: TComponent); override;');
- AddToInterface(' property ComServer:%s read fServer;',[sDefIntf]);
- AddToInterface(FEventProperties[idx]);
- AddToInterFace(' end;');
- AddToInterFace('');
- end;
- AddToImplementation('Class Function Co%s.Create: %s;',[BstrName,sDefIntf]);
- AddToImplementation('begin');
- AddToImplementation(' Result := CreateComObject(CLASS_%s) as %s;',[BstrName,sDefIntf]);
- AddToImplementation('end;');
- AddToImplementation('');
- AddToImplementation('Class Function Co%s.CreateRemote(const MachineName: string): %s;',[BstrName,sDefIntf]);
- AddToImplementation('begin');
- AddToImplementation(' Result := CreateRemoteComObject(MachineName,CLASS_%s) as %s;',[BstrName,sDefIntf]);
- AddToImplementation('end;');
- AddToImplementation('');
- if FActiveX then
- begin
- AddToImplementation('constructor T%s.Create(TheOwner: TComponent);',[BstrName]);
- AddToImplementation('begin');
- AddToImplementation(' inherited Create(TheOwner);');
- AddToImplementation(' FServer:=Co%s.Create;',[BstrName]);
- AddToImplementation(' ComServer:=FServer;',[BstrName]);
- if (sDefEvents<>'') then
- begin
- AddToImplementation(' FEventSink:=TEventSink.Create(Self);');
- AddToImplementation(' FEventSink.OnInvoke:=EventSinkInvoke;');
- AddToImplementation(' FEventSink.Connect(FServer,%s);',[FEventDisp[idx]]);
- end;
- AddToImplementation('end;');
- AddToImplementation('');
- AddToImplementation('destructor T%s.Destroy;',[BstrName]);
- AddToImplementation('begin');
- if (sDefEvents<>'') then
- AddToImplementation(' FEventSink.Destroy;');
- AddToImplementation(' inherited destroy;');
- AddToImplementation('end;');
- AddToImplementation('');
- if (sDefEvents<>'') then
- begin
- AddToImplementation('procedure T%s.EventSinkInvoke(Sender: TObject; DispID: Integer;',[BstrName]);
- AddToImplementation(' const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS;');
- AddToImplementation(' VarResult, ExcepInfo, ArgErr: Pointer);');
- AddToImplementation('begin');
- AddToImplementation(' case DispID of');
- AddToImplementation(FEventImplementations[idx]);
- AddToImplementation(' end;');
- AddToImplementation('end;');
- AddToImplementation('');
- end;
- end
- else if sDefEvents<>'' then //add event implementations
- begin
- AddToImplementation('constructor T%s.Create(TheOwner: TComponent);',[BstrName]);
- AddToImplementation('begin');
- AddToImplementation(' inherited Create(TheOwner);');
- AddToImplementation(' OnInvoke:=EventSinkInvoke;');
- AddToImplementation(' fServer:=Co%s.Create;',[BstrName]);
- AddToImplementation(' Connect(fServer,%s);',[FEventDisp[idx]]);
- AddToImplementation('end;');
- AddToImplementation('');
- AddToImplementation('procedure T%s.EventSinkInvoke(Sender: TObject; DispID: Integer;',[BstrName]);
- AddToImplementation(' const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS;');
- AddToImplementation(' VarResult, ExcepInfo, ArgErr: Pointer);');
- AddToImplementation('begin');
- AddToImplementation(' case DispID of');
- AddToImplementation(FEventImplementations[idx]);
- AddToImplementation(' end;');
- AddToImplementation('end;');
- AddToImplementation('');
- end;
- TI.ReleaseTypeAttr(TA);
- end;
- end;
- end;
- Procedure TTypeLibImporter.CreateUnitHeader(Const TL : ITypeLib; const LA: lpTLIBATTR);
- Var
- BstrName, BstrDocString, BstrHelpFile : WideString;
- dwHelpContext: DWORD;
- begin
- OleCheck(TL.GetDocumentation(-1, @BstrName, @BstrDocString, @dwHelpContext, @BstrHelpFile));
- if (UnitName='') then
- if FAppendVersionNumber then
- UnitName:=format('%s_%d_%d_TLB',[BstrName,LA^.wMajorVerNum,LA^.wMinorVerNum])
- else
- UnitName:=format('%s_TLB',[BstrName]);
- //header
- AddToHeader('Unit %s;',[UnitName],True);
- AddToHeader('',true);
- AddToHeader('// Imported %s on %s from %s',[BstrName,DateTimeToStr(Now()),InputFilename],True);
- AddToHeader('',true);
- AddToHeader('{$mode delphi}{$H+}',true);
- AddToHeader('',true);
- AddToHeader('interface',true);
- AddToHeader('',true);
- FUses.Add('Windows');
- FUses.Add('ActiveX');
- FUses.Add('Classes');
- //FUses.Add('OleServer');
- FUses.Add('Variants');
- AddToInterface('Const');
- AddToInterface(' %sMajorVersion = %d;',[BstrName,LA^.wMajorVerNum]);
- AddToInterface(' %sMinorVersion = %d;',[BstrName,LA^.wMinorVerNum]);
- AddToInterface(' %sLCID = %x;',[BstrName,LA^.LCID]);
- AddToInterface(' LIBID_%s : TGUID = ''%s'';',[BstrName,GUIDToString(LA^.GUID)]);
- AddToInterface('');
- end;
- Procedure TTypeLibImporter.DoImportTypelib;
- var
- TL: ITypelib;
- TIcount:integer;
- LA: lpTLIBATTR;
- begin
- Header.Clear;
- InterfaceSection.Clear;
- OleCheck(LoadTypeLib(PWidechar(InputFileName), TL ));
- OleCheck(TL.GetLibAttr(LA));
- try
- CreateUnitHeader(TL,LA);
- TIcount:=TL.GetTypeInfoCount;
- ImportGUIDs(TL,TICount);
- ImportEnums(TL,TICount);
- CreateForwards(TL,TICount);
- CreateRecordsUnionsAliases(TL,TICount);
- CreateInterFaces(TL,TICount);
- CreateCoClasses(TL,TICount);
- finally
- TL.ReleaseTLibAttr(LA);
- end;
- BuildUnit;
- end;
- procedure TTypeLibImporter.BuildUnit;
- Var
- l : string;
- I : Integer;
- begin
- UnitSource.AddStrings(Header);
- UnitSource.Add('Uses');
- L:=' ';
- For I:=0 to FUses.Count-1 do
- begin
- L:=L+FUses[i];
- If (I<Fuses.Count-1) then
- L:=L+','
- else
- L:=L+';';
- if (Length(L)>72) then
- begin
- UnitSource.Add(L);
- L:=' ';
- end;
- end;
- if (L<>' ') then
- UnitSource.Add(L);
- UnitSource.addStrings(InterfaceSection);
- UnitSource.addStrings(ImplementationSection);
- UnitSource.Add('end.');
- end;
- { TTypeLibImporter }
- procedure TTypeLibImporter.SetOutputFileName(AValue: String);
- Var
- UN : String;
- begin
- if FOutputFileName=AValue then Exit;
- UN:=ChangeFileExt(ExtractFileName(AValue),'');
- if not IsValidIdent(UN) then
- Raise Exception.CreateFmt(SErrInvalidUnitName,[UN]);
- FOutputFileName:=AValue;
- SetUnitName(UN)
- end;
- procedure TTypeLibImporter.SetUnitName(AValue: string);
- begin
- if FUnitname=AValue then Exit;
- if not IsValidIdent(AVAlue) then
- Raise Exception.CreateFmt(SErrInvalidUnitName,[AValue]);
- FUnitname:=AValue;
- if (OutputFileName<>'') then
- OutputFileName:=ExtractFilePath(OutputFileName)+UnitName+'.pas';
- end;
- procedure TTypeLibImporter.AddToUses(const AUnit: String);
- begin
- If FUses.IndexOf(AUnit)=-1 then
- FUses.add(AUnit);
- end;
- procedure TTypeLibImporter.AddToHeader(const ALine: String;
- AllowDuplicate: Boolean);
- begin
- If (AllowDuplicate) or (FHeader.IndexOf(ALine)=-1) then
- FHeader.Add(ALine);
- end;
- procedure TTypeLibImporter.AddToHeader(const Fmt: String; Args: array of const;
- AllowDuplicate: Boolean);
- begin
- AddToheader(Format(Fmt,Args),AllowDuplicate)
- end;
- procedure TTypeLibImporter.AddToInterface(const ALine: String);
- begin
- FInterface.Add(ALine);
- end;
- procedure TTypeLibImporter.AddToInterface(const Fmt: String;
- Args: array of const);
- begin
- FInterface.Add(Format(Fmt,Args));
- end;
- procedure TTypeLibImporter.AddToImplementation(const ALine: String);
- begin
- FImplementation.Add(ALine);
- end;
- procedure TTypeLibImporter.AddToImplementation(const Fmt: String;
- Args: array of const);
- begin
- FImplementation.Add(Format(Fmt,Args));
- end;
- constructor TTypeLibImporter.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FDependencies:=TStringList.Create;
- FUnitSource:=TStringList.Create;
- FAppendVersionNumber:=true;
- end;
- destructor TTypeLibImporter.Destroy;
- begin
- FreeAndNil(FDependencies);
- FreeAndNil(FUnitSource);
- inherited Destroy;
- end;
- procedure TTypeLibImporter.Execute;
- begin
- FDependencies.Clear;
- FUnitSource.Clear;
- FHeader:=TStringList.Create;
- FInterface:=TStringList.Create;
- FImplementation:=TStringList.Create;
- FUses:=TStringList.Create;
- FTypes:=TStringList.Create;
- FEventDisp:=TStringList.Create;
- FEventIID:=TStringList.Create;
- FEventSignatures:=TStringList.Create;
- FEventFunctions:=TStringList.Create;
- FEventProperties:=TStringList.Create;
- FEventImplementations:=TStringList.Create;
- try
- DoImportTypeLib;
- If (OutputFileName<>'') then
- UnitSource.SaveToFile(OutputFileName);
- finally
- FreeAndNil(FEventImplementations);
- FreeAndNil(FEventProperties);
- FreeAndNil(FEventFunctions);
- FreeAndNil(FEventSignatures);
- FreeAndNil(FEventIID);
- FreeAndNil(FEventDisp);
- FreeAndNil(FTypes);
- FreeAndNil(FUses);
- FreeAndNil(FInterface);
- FreeAndNil(FHeader);
- FreeAndNil(FImplementation);
- end;
- end;
- end.
|