home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / full / delphi / RUNIMAGE / DELPHI30 / SOURCE / VCL / OLEAUTO.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-08-03  |  41.6 KB  |  1,553 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Visual Component Library                 }
  5. {                                                       }
  6. {       Copyright (c) 1996,97 Borland International     }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit OleAuto;
  11.  
  12. {$DENYPACKAGEUNIT}
  13.  
  14. { OleAuto cannot be used in a package DLL.  To implement
  15.   an OLE automation server in a package, use the new
  16.   OLE automation support in comobj and comserv.
  17. }
  18.  
  19. {$R-}
  20.  
  21. interface
  22.  
  23. uses Windows, Ole2, OleCtl, SysUtils;
  24.  
  25. const
  26.  
  27. { Maximum number of dispatch arguments }
  28.  
  29.   MaxDispArgs = 32;
  30.  
  31. type
  32.  
  33. { Forward declarations }
  34.  
  35.   TAutoObject = class;
  36.  
  37. { Dispatch interface for TAutoObject }
  38.  
  39.   TAutoDispatch = class(IDispatch)
  40.   private
  41.     FAutoObject: TAutoObject;
  42.   public
  43.     constructor Create(AutoObject: TAutoObject);
  44.     function QueryInterface(const iid: TIID; var obj): HResult; override;
  45.     function AddRef: Longint; override;
  46.     function Release: Longint; override;
  47.     function GetTypeInfoCount(var ctinfo: Integer): HResult; override;
  48.     function GetTypeInfo(itinfo: Integer; lcid: TLCID;
  49.       var tinfo: ITypeInfo): HResult; override;
  50.     function GetIDsOfNames(const iid: TIID; rgszNames: POleStrList;
  51.       cNames: Integer; lcid: TLCID; rgdispid: PDispIDList): HResult; override;
  52.     function Invoke(dispIDMember: TDispID; const iid: TIID; lcid: TLCID;
  53.       flags: Word; var dispParams: TDispParams; varResult: PVariant;
  54.       excepInfo: PExcepInfo; argErr: PInteger): HResult; override;
  55.     function GetAutoObject: TAutoObject; virtual; stdcall;
  56.     property AutoObject: TAutoObject read FAutoObject;
  57.   end;
  58.  
  59. { TAutoObject - Automation object base class. An automation class is
  60.   implemented by deriving a new class from TAutoObject, and declaring methods
  61.   and properties in an "automated" section in the new class. To expose an
  62.   automation class to external OLE Automation Controllers, the unit that
  63.   implements the automation class must call Automation.RegisterClass in its
  64.   initialization section, passing in a TAutoClassInfo structure. Once a
  65.   class has been registered in this way, the global Automation object
  66.   automatically manages all aspects of interfacing with the OLE Automation
  67.   APIs.
  68.  
  69.   When an external OLE Automation Controller requests an instance of an
  70.   automation class, the Create constructor is called to create the object,
  71.   and when all external references to the object disappear, the Destroy
  72.   destructor is called to destroy the object. As is the case with all OLE
  73.   objects, automation objects are reference counted. }
  74.  
  75.   TAutoObject = class(TObject)
  76.   private
  77.     FRefCount: Integer;
  78.     FAutoDispatch: TAutoDispatch;
  79.     function GetIDsOfNames(Names: POleStrList; Count: Integer;
  80.       DispIDs: PDispIDList): HResult;
  81.     function GetOleObject: Variant;
  82.     function Invoke(DispID: TDispID; Flags: Integer; var Params: TDispParams;
  83.       VarResult: PVariant; ExcepInfo: PExcepInfo; ArgErr: PInteger): HResult;
  84.     procedure InvokeMethod(AutoEntry, Args, Result: Pointer);
  85.     function QueryInterface(const iid: TIID; var obj): HResult;
  86.   protected
  87.     function CreateAutoDispatch: TAutoDispatch; virtual;
  88.     procedure GetExceptionInfo(ExceptObject: TObject;
  89.       var ExcepInfo: TExcepInfo); virtual;
  90.   public
  91.     constructor Create; virtual;
  92.     destructor Destroy; override;
  93.     function AddRef: Integer;
  94.     function Release: Integer;
  95.     property AutoDispatch: TAutoDispatch read FAutoDispatch;
  96.     property OleObject: Variant read GetOleObject;
  97.     property RefCount: Integer read FRefCount;
  98.   end;
  99.  
  100. { Automation object class reference }
  101.  
  102.   TAutoClass = class of TAutoObject;
  103.  
  104. { Instancing mode for local server automation classes }
  105.  
  106.   TAutoClassInstancing = (acInternal, acSingleInstance, acMultiInstance);
  107.  
  108. { Automation class registration info }
  109.  
  110.   TAutoClassInfo = record
  111.     AutoClass: TAutoClass;
  112.     ProgID: string;
  113.     ClassID: string;
  114.     Description: string;
  115.     Instancing: TAutoClassInstancing;
  116.   end;
  117.  
  118. { Class registry entry }
  119.  
  120.   TRegistryClass = class
  121.   private
  122.     FNext: TRegistryClass;
  123.     FAutoClass: TAutoClass;
  124.     FProgID: string;
  125.     FClassID: TCLSID;
  126.     FDescription: string;
  127.     FInstancing: TAutoClassInstancing;
  128.     FRegister: Longint;
  129.   public
  130.     constructor Create(const AutoClassInfo: TAutoClassInfo);
  131.     destructor Destroy; override;
  132.     procedure UpdateRegistry(Register: Boolean);
  133.   end;
  134.  
  135. { Application start mode }
  136.  
  137.   TStartMode = (smStandalone, smAutomation, smRegServer, smUnregServer);
  138.  
  139. { Automation manager event types }
  140.  
  141.   TLastReleaseEvent = procedure(var Shutdown: Boolean) of object;
  142.  
  143. { Automation manager object }
  144.  
  145.   TAutomation = class
  146.   private
  147.     FRegistryList: TRegistryClass;
  148.     FAutoObjectCount: Integer;
  149.     FClassFactoryCount: Integer;
  150.     FIsInprocServer: Boolean;
  151.     FStartMode: TStartMode;
  152.     FOnLastRelease: TLastReleaseEvent;
  153.     procedure CountAutoObject(Created: Boolean);
  154.     procedure Initialize;
  155.     procedure LastReleased;
  156.   public
  157.     constructor Create;
  158.     destructor Destroy; override;
  159.     procedure RegisterClass(const AutoClassInfo: TAutoClassInfo);
  160.     procedure UpdateRegistry(Register: Boolean);
  161.     property AutoObjectCount: Integer read FAutoObjectCount;
  162.     property IsInprocServer: Boolean read FIsInprocServer write FIsInprocServer;
  163.     property StartMode: TStartMode read FStartMode;
  164.     property OnLastRelease: TLastReleaseEvent read FOnLastRelease write FOnLastRelease;
  165.   end;
  166.  
  167. { OLE exception classes }
  168.  
  169.   EOleError = class(Exception);
  170.  
  171.   EOleSysError = class(EOleError)
  172.   private
  173.     FErrorCode: Integer;
  174.   public
  175.     constructor Create(ErrorCode: Integer);
  176.     property ErrorCode: Integer read FErrorCode;
  177.   end;
  178.  
  179.   EOleException = class(EOleError)
  180.   private
  181.     FErrorCode: Integer;
  182.     FSource: string;
  183.     FHelpFile: string;
  184.   public
  185.     constructor Create(const ExcepInfo: TExcepInfo);
  186.     property ErrorCode: Integer read FErrorCode;
  187.     property HelpFile: string read FHelpFile;
  188.     property Source: string read FSource;
  189.   end;
  190.  
  191. { Dispatch call descriptor }
  192.  
  193.   PCallDesc = ^TCallDesc;
  194.   TCallDesc = packed record
  195.     CallType: Byte;
  196.     ArgCount: Byte;
  197.     NamedArgCount: Byte;
  198.     ArgTypes: array[0..255] of Byte;
  199.   end;
  200.  
  201. var
  202.   Automation: TAutomation;
  203.  
  204. { CreateOleObject creates an OLE automation object of the given class. }
  205.  
  206. function CreateOleObject(const ClassName: string): Variant;
  207.  
  208. { GetActiveOleObject returns the active object for the given class. }
  209.  
  210. function GetActiveOleObject(const ClassName: string): Variant;
  211.  
  212. { The DllXXXX routines implement the required entry points of an in-process
  213.   automation server DLL. These routines must be exported by the DLL using
  214.   an "exports" clause in the library's main module. }
  215.  
  216. function DllGetClassObject(const CLSID: TCLSID; const IID: TIID;
  217.   var Obj): HResult; stdcall;
  218. function DllCanUnloadNow: HResult; stdcall;
  219. function DllRegisterServer: HResult; stdcall;
  220. function DllUnregisterServer: HResult; stdcall;
  221.  
  222. { VarFromInterface returns a variant that contains the a reference to the
  223.   IDispatch interface of the given IUnknown interface. If the Unknown
  224.   parameter is NIL, the resulting variant is set to Unassigned. }
  225.  
  226. function VarFromInterface(Unknown: IUnknown): Variant;
  227.  
  228. { VarToInterface returns the IDispatch interface reference stored in the
  229.   given variant. An exception is raised if the variant does not contain
  230.   an IDispatch interface. VarToInterface does not affect the reference
  231.   count of the returned IDispatch. The caller of VarToInterface must
  232.   manually call AddRef and Release on the returned interface. }
  233.  
  234. function VarToInterface(const V: Variant): IDispatch;
  235.  
  236. { VarToAutoObject returns the TAutoObject instance corresponding to the
  237.   IDispatch interface reference stored in the given variant. An exception
  238.   is raised if the variant does not contain an IDispatch interface, or if
  239.   the IDispatch interface is not that of a TAutoObject instance. }
  240.  
  241. function VarToAutoObject(const V: Variant): TAutoObject;
  242.  
  243. procedure DispInvoke(Dispatch: IDispatch; CallDesc: PCallDesc;
  244.   DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  245. procedure DispInvokeError(Status: Integer; const ExcepInfo: TExcepInfo);
  246.  
  247. procedure OleError(ErrorCode: HResult);
  248. procedure OleCheck(Result: HResult);
  249.  
  250. function StringToClassID(const S: string): TCLSID;
  251. function ClassIDToString(const ClassID: TCLSID): string;
  252.  
  253. function ProgIDToClassID(const ProgID: string): TCLSID;
  254. function ClassIDToProgID(const ClassID: TCLSID): string;
  255.  
  256. implementation
  257.  
  258. uses OleConst, ComObj;
  259.  
  260. const
  261.  
  262. { Special variant type codes }
  263.  
  264.   varStrArg = $0048;
  265.  
  266. { Parameter type masks }
  267.  
  268.   atVarMask  = $3F;
  269.   atTypeMask = $7F;
  270.   atByRef    = $80;
  271.  
  272. { Automation entry flags }
  273.  
  274.   afMethod  = $00000001;
  275.   afPropGet = $00000002;
  276.   afPropSet = $00000004;
  277.   afVirtual = $00000008;
  278.  
  279. type
  280.  
  281. { Automation entry parameter list }
  282.  
  283.   PParamList = ^TParamList;
  284.   TParamList = record
  285.     ResType: Byte;
  286.     ParamCount: Byte;
  287.     ParamTypes: array[0..255] of Byte;
  288.   end;
  289.  
  290. { Automation table entry }
  291.  
  292.   PAutoEntry = ^TAutoEntry;
  293.   TAutoEntry = record
  294.     DispID: Integer;
  295.     Name: PShortString;
  296.     Flags: Integer;
  297.     Params: PParamList;
  298.     Address: Pointer;
  299.   end;
  300.  
  301. { Automation table layout }
  302.  
  303.   PAutoTable = ^TAutoTable;
  304.   TAutoTable = record
  305.     EntryCount: Integer;
  306.     Entries: array[0..4095] of TAutoEntry;
  307.   end;
  308.  
  309. { Class factory }
  310.  
  311.   TClassFactory = class(IClassFactory)
  312.   private
  313.     FRefCount: Integer;
  314.     FAutoClass: TAutoClass;
  315.   public
  316.     constructor Create(AutoClass: TAutoClass);
  317.     destructor Destroy; override;
  318.     function QueryInterface(const iid: TIID; var obj): HResult; override;
  319.     function AddRef: Longint; override;
  320.     function Release: Longint; override;
  321.     function CreateInstance(unkOuter: IUnknown; const iid: TIID;
  322.       var obj): HResult; override;
  323.     function LockServer(fLock: BOOL): HResult; override;
  324.   end;
  325.  
  326. { IAutoDispatch interface ID }
  327.  
  328. const
  329.   IID_IAutoDispatch: TGUID = ( {F5B2B8E0-1627-11CF-BD2F-0020AF0E5B81}
  330.     D1:$F5B2B8E0;D2:$1627;D3:$11CF;D4:($BD,$2F,$00,$20,$AF,$0E,$5B,$81));
  331.  
  332. { Raise EOleSysError exception from an error code }
  333.  
  334. procedure OleError(ErrorCode: HResult);
  335. begin
  336.   raise EOleSysError.Create(ErrorCode);
  337. end;
  338.  
  339. { Raise EOleSysError exception if result code indicates an error }
  340.  
  341. procedure OleCheck(Result: HResult);
  342. begin
  343.   if Result < 0 then OleError(Result);
  344. end;
  345.  
  346. { Convert a string to a class ID }
  347.  
  348. function StringToClassID(const S: string): TCLSID;
  349. var
  350.   Buffer: array[0..127] of WideChar;
  351. begin
  352.   OleCheck(CLSIDFromString(StringToWideChar(S, Buffer,
  353.     SizeOf(Buffer) div 2), Result));
  354. end;
  355.  
  356. { Convert a class ID to a string }
  357.  
  358. function ClassIDToString(const ClassID: TCLSID): string;
  359. var
  360.   P: PWideChar;
  361. begin
  362.   OleCheck(StringFromCLSID(ClassID, P));
  363.   Result := WideCharToString(P);
  364.   CoTaskMemFree(P);
  365. end;
  366.  
  367. { Convert a programmatic ID to a class ID }
  368.  
  369. function ProgIDToClassID(const ProgID: string): TCLSID;
  370. var
  371.   Buffer: array[0..127] of WideChar;
  372. begin
  373.   OleCheck(CLSIDFromProgID(StringToWideChar(ProgID, Buffer,
  374.     SizeOf(Buffer) div 2), Result));
  375. end;
  376.  
  377. { Convert a class ID to a programmatic ID }
  378.  
  379. function ClassIDToProgID(const ClassID: TCLSID): string;
  380. var
  381.   P: PWideChar;
  382. begin
  383.   OleCheck(ProgIDFromCLSID(ClassID, P));
  384.   Result := WideCharToString(P);
  385.   CoTaskMemFree(P);
  386. end;
  387.  
  388. { Create registry key }
  389.  
  390. procedure CreateRegKey(const Key, Value: string);
  391. begin
  392.   RegSetValue(HKEY_CLASSES_ROOT, PChar(Key), REG_SZ, PChar(Value),
  393.     Length(Value));
  394. end;
  395.  
  396. { Delete registry key }
  397.  
  398. procedure DeleteRegKey(const Key: string);
  399. begin
  400.   RegDeleteKey(HKEY_CLASSES_ROOT, PChar(Key));
  401. end;
  402.  
  403. { Get server key name }
  404.  
  405. function GetServerKey: string;
  406. begin
  407.   if Automation.IsInprocServer then
  408.     Result := 'InprocServer32' else
  409.     Result := 'LocalServer32';
  410. end;
  411.  
  412. { Find command-line switch }
  413.  
  414. function FindCmdLineSwitch(const Switch: string): Boolean;
  415. var
  416.   I: Integer;
  417.   S: string;
  418. begin
  419.   for I := 1 to ParamCount do
  420.   begin
  421.     S := ParamStr(I);
  422.     if (S[1] in ['-', '/']) and
  423.       (CompareText(Copy(S, 2, Maxint), Switch) = 0) then
  424.     begin
  425.       Result := True;
  426.       Exit;
  427.     end;
  428.   end;
  429.   Result := False;
  430. end;
  431.  
  432. { Convert wide character string to ShortString }
  433.  
  434. procedure WideCharToShortString(P: PWideChar; var S: ShortString);
  435. var
  436.   I: Integer;
  437.   W: WideChar;
  438. begin
  439.   I := 0;
  440.   repeat
  441.     W := P[I];
  442.     if W = #0 then Break;
  443.     if W >= #256 then W := #0;
  444.     Inc(I);
  445.     S[I] := Char(W);
  446.   until I = 255;
  447.   S[0] := Char(I);
  448. end;
  449.  
  450. { Compare two symbols }
  451.  
  452. function SameSymbol(const Ident1, Ident2: ShortString): Boolean;
  453. asm
  454.         PUSH    EBX
  455.         XOR     EBX,EBX
  456.         XOR     ECX,ECX
  457.         MOV     CL,[EAX]
  458.         CMP     CL,[EDX]
  459.         JNE     @@2
  460. @@1:    MOV     BH,[EAX+ECX]
  461.         XOR     BH,[EDX+ECX]
  462.         TEST    BH,0DFH
  463.         JNE     @@2
  464.         DEC     ECX
  465.         JNE     @@1
  466.         INC     EBX
  467. @@2:    XOR     EAX,EAX
  468.         MOV     AL,BL
  469.         POP     EBX
  470. end;
  471.  
  472. { Return automation table of the given class }
  473.  
  474. function GetAutoTable(ClassRef: TClass): PAutoTable;
  475. asm
  476.         MOV     EAX,[EAX].vmtAutoTable
  477. end;
  478.  
  479. { Return dispatch ID of the given name in the given class }
  480.  
  481. function GetDispIDOfName(ClassRef: TClass; const Name: ShortString): Integer;
  482. var
  483.   AutoTable: PAutoTable;
  484.   NameStart: Word;
  485.   I: Integer;
  486.   P: PAutoEntry;
  487. begin
  488.   NameStart := Word((@Name)^);
  489.   repeat
  490.     AutoTable := GetAutoTable(ClassRef);
  491.     if AutoTable <> nil then
  492.     begin
  493.       I := AutoTable^.EntryCount;
  494.       P := @AutoTable^.Entries;
  495.       repeat
  496.         if ((NameStart xor Word(Pointer(P^.Name)^)) and $DFFF = 0) and
  497.           SameSymbol(Name, P^.Name^) then
  498.         begin
  499.           Result := P^.DispID;
  500.           Exit;
  501.         end;
  502.         Inc(Integer(P), SizeOf(TAutoEntry));
  503.         Dec(I);
  504.       until I = 0;
  505.     end;
  506.     ClassRef := ClassRef.ClassParent;
  507.   until ClassRef = nil;
  508.   Result := -1;
  509. end;
  510.  
  511. { Return automation table entry for the given dispatch ID and dispatch
  512.   flags in the given class }
  513.  
  514. function GetAutoEntry(ClassRef: TClass; DispID, Flags: Integer): PAutoEntry;
  515. var
  516.   AutoTable: PAutoTable;
  517.   I: Integer;
  518. begin
  519.   repeat
  520.     AutoTable := GetAutoTable(ClassRef);
  521.     if AutoTable <> nil then
  522.     begin
  523.       I := AutoTable^.EntryCount;
  524.       Result := @AutoTable^.Entries;
  525.       repeat
  526.         if (Result^.DispID = DispID) and
  527.           (Result^.Flags and Flags <> 0) then Exit;
  528.         Inc(Integer(Result), SizeOf(TAutoEntry));
  529.         Dec(I);
  530.       until I = 0;
  531.     end;
  532.     ClassRef := ClassRef.ClassParent;
  533.   until ClassRef = nil;
  534.   Result := nil;
  535. end;
  536.  
  537. { Create an OLE object variant given an IDispatch }
  538.  
  539. function VarFromInterface(Unknown: IUnknown): Variant;
  540. var
  541.   Dispatch: IDispatch;
  542. begin
  543.   VarClear(Result);
  544.   if Unknown <> nil then
  545.   begin
  546.     OleCheck(Unknown.QueryInterface(IID_IDispatch, Dispatch));
  547.     TVarData(Result).VType := varDispatch;
  548.     TVarData(Result).VDispatch := Dispatch;
  549.   end;
  550. end;
  551.  
  552. { Return OLE object stored in a variant }
  553.  
  554. function VarToInterface(const V: Variant): IDispatch;
  555. begin
  556.   Result := nil;
  557.   if TVarData(V).VType = varDispatch then
  558.     Result := TVarData(V).VDispatch
  559.   else if TVarData(V).VType = (varDispatch or varByRef) then
  560.     Result := Pointer(TVarData(V).VPointer^);
  561.   if Result = nil then raise EOleError.Create(SVarNotObject);
  562. end;
  563.  
  564. { Return TAutoObject referenced by the given variant }
  565.  
  566. function VarToAutoObject(const V: Variant): TAutoObject;
  567. var
  568.   Dispatch: IDispatch;
  569.   AutoDispatch: TAutoDispatch;
  570. begin
  571.   Dispatch := VarToInterface(V);
  572.   if Dispatch.QueryInterface(IID_IAutoDispatch, AutoDispatch) <> S_OK then
  573.     raise EOleError.Create(SVarNotAutoObject);
  574.   Result := AutoDispatch.GetAutoObject;
  575.   AutoDispatch.Release;
  576. end;
  577.  
  578. { Create an OLE object variant given a class name }
  579.  
  580. function CreateOleObject(const ClassName: string): Variant;
  581. var
  582.   Unknown: IUnknown;
  583.   ClassID: TCLSID;
  584.   WideCharBuf: array[0..127] of WideChar;
  585. begin
  586.   StringToWideChar(ClassName, WideCharBuf, SizeOf(WideCharBuf) div 2);
  587.   OleCheck(CLSIDFromProgID(WideCharBuf, ClassID));
  588.   OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
  589.     CLSCTX_LOCAL_SERVER, IID_IUnknown, Unknown));
  590.   try
  591.     Result := VarFromInterface(Unknown);
  592.   finally;
  593.     Unknown.Release;
  594.   end;
  595. end;
  596.  
  597. { Get active OLE object for a given class name }
  598.  
  599. function GetActiveOleObject(const ClassName: string): Variant;
  600. var
  601.   Unknown: IUnknown;
  602.   ClassID: TCLSID;
  603.   WideCharBuf: array[0..127] of WideChar;
  604. begin
  605.   StringToWideChar(ClassName, WideCharBuf, SizeOf(WideCharBuf) div 2);
  606.   OleCheck(CLSIDFromProgID(WideCharBuf, ClassID));
  607.   OleCheck(GetActiveObject(ClassID, nil, Unknown));
  608.   try
  609.     Result := VarFromInterface(Unknown);
  610.   finally;
  611.     Unknown.Release;
  612.   end;
  613. end;
  614.  
  615. { Call Invoke method on the given IDispatch interface using the given
  616.   call descriptor, dispatch IDs, parameters, and result }
  617.  
  618. procedure DispInvoke(Dispatch: IDispatch; CallDesc: PCallDesc;
  619.   DispIDs: PDispIDList; Params: Pointer; Result: PVariant);
  620. type
  621.   PVarArg = ^TVarArg;
  622.   TVarArg = array[0..3] of Integer;
  623.   TStringDesc = record
  624.     BStr: PWideChar;
  625.     PStr: PString;
  626.   end;
  627. var
  628.   I, J, K, ArgType, ArgCount, StrCount, DispID, InvKind, Status: Integer;
  629.   VarFlag: Byte;
  630.   ParamPtr: ^Integer;
  631.   ArgPtr, VarPtr: PVarArg;
  632.   DispParams: TDispParams;
  633.   ExcepInfo: TExcepInfo;
  634.   Strings: array[0..MaxDispArgs - 1] of TStringDesc;
  635.   Args: array[0..MaxDispArgs - 1] of TVarArg;
  636. begin
  637.   StrCount := 0;
  638.   try
  639.     ArgCount := CallDesc^.ArgCount;
  640.     if ArgCount <> 0 then
  641.     begin
  642.       ParamPtr := Params;
  643.       ArgPtr := @Args[ArgCount];
  644.       I := 0;
  645.       repeat
  646.         Dec(Integer(ArgPtr), SizeOf(TVarData));
  647.         ArgType := CallDesc^.ArgTypes[I] and atTypeMask;
  648.         VarFlag := CallDesc^.ArgTypes[I] and atByRef;
  649.         if ArgType = varError then
  650.         begin
  651.           ArgPtr^[0] := varError;
  652.           ArgPtr^[2] := DISP_E_PARAMNOTFOUND;
  653.         end else
  654.         begin
  655.           if ArgType = varStrArg then
  656.           begin
  657.             with Strings[StrCount] do
  658.               if VarFlag <> 0 then
  659.               begin
  660.                 BStr := StringToOleStr(PString(ParamPtr^)^);
  661.                 PStr := PString(ParamPtr^);
  662.                 ArgPtr^[0] := varOleStr or varByRef;
  663.                 ArgPtr^[2] := Integer(@BStr);
  664.               end else
  665.               begin
  666.                 BStr := StringToOleStr(PString(ParamPtr)^);
  667.                 PStr := nil;
  668.                 ArgPtr^[0] := varOleStr;
  669.                 ArgPtr^[2] := Integer(BStr);
  670.               end;
  671.             Inc(StrCount);
  672.           end else
  673.           if VarFlag <> 0 then
  674.           begin
  675.             if (ArgType = varVariant) and
  676.               (PVarData(ParamPtr^)^.VType = varString) then
  677.               VarCast(PVariant(ParamPtr^)^, PVariant(ParamPtr^)^, varOleStr);
  678.             ArgPtr^[0] := ArgType or varByRef;
  679.             ArgPtr^[2] := ParamPtr^;
  680.           end else
  681.           if ArgType = varVariant then
  682.           begin
  683.             if PVarData(ParamPtr^)^.VType = varString then
  684.             begin
  685.               with Strings[StrCount] do
  686.               begin
  687.                 BStr := StringToOleStr(string(PVarData(ParamPtr^)^.VString));
  688.                 PStr := nil;
  689.                 ArgPtr^[0] := varOleStr;
  690.                 ArgPtr^[2] := Integer(BStr);
  691.               end;
  692.               Inc(StrCount);
  693.             end else
  694.             begin
  695.               VarPtr := PVarArg(ParamPtr^);
  696.               ArgPtr^[0] := VarPtr^[0];
  697.               ArgPtr^[1] := VarPtr^[1];
  698.               ArgPtr^[2] := VarPtr^[2];
  699.               ArgPtr^[3] := VarPtr^[3];
  700.             end;
  701.           end else
  702.           begin
  703.             ArgPtr^[0] := ArgType;
  704.             ArgPtr^[2] := ParamPtr^;
  705.             if (ArgType >= varDouble) and (ArgType <= varDate) then
  706.             begin
  707.               Inc(Integer(ParamPtr), 4);
  708.               ArgPtr^[3] := ParamPtr^;
  709.             end;
  710.           end;
  711.           Inc(Integer(ParamPtr), 4);
  712.         end;
  713.         Inc(I);
  714.       until I = ArgCount;
  715.     end;
  716.     DispParams.rgvarg := @Args;
  717.     DispParams.rgdispidNamedArgs := @DispIDs[1];
  718.     DispParams.cArgs := ArgCount;
  719.     DispParams.cNamedArgs := CallDesc^.NamedArgCount;
  720.     DispID := DispIDs[0];
  721.     InvKind := CallDesc^.CallType;
  722.     if InvKind = DISPATCH_PROPERTYPUT then
  723.     begin
  724.       if Args[0][0] and varTypeMask = varDispatch then
  725.         InvKind := DISPATCH_PROPERTYPUTREF;
  726.       DispIDs[0] := DISPID_PROPERTYPUT;
  727.       Dec(Integer(DispParams.rgdispidNamedArgs), SizeOf(Integer));
  728.       Inc(DispParams.cNamedArgs);
  729.     end else
  730.       if (InvKind = DISPATCH_METHOD) and (ArgCount = 0) and (Result <> nil) then
  731.         InvKind := DISPATCH_METHOD or DISPATCH_PROPERTYGET;
  732.     Status := Dispatch.Invoke(DispID, GUID_NULL, 0, InvKind, DispParams,
  733.       Result, @ExcepInfo, nil);
  734.     if Status <> 0 then DispInvokeError(Status, ExcepInfo);
  735.     J := StrCount;
  736.     while J <> 0 do
  737.     begin
  738.       Dec(J);
  739.       with Strings[J] do
  740.         if PStr <> nil then OleStrToStrVar(BStr, PStr^);
  741.     end;
  742.   finally
  743.     K := StrCount;
  744.     while K <> 0 do
  745.     begin
  746.       Dec(K);
  747.       SysFreeString(Strings[K].BStr);
  748.     end;
  749.   end;
  750. end;
  751.  
  752. { Raise exception given an OLE return code and TExcepInfo structure }
  753.  
  754. procedure DispInvokeError(Status: Integer; const ExcepInfo: TExcepInfo);
  755. var
  756.   E: EOleException;
  757. begin
  758.   if Status <> DISP_E_EXCEPTION then OleError(Status);
  759.   E := EOleException.Create(ExcepInfo);
  760.   with ExcepInfo do
  761.   begin
  762.     if bstrSource <> nil then SysFreeString(bstrSource);
  763.     if bstrDescription <> nil then SysFreeString(bstrDescription);
  764.     if bstrHelpFile <> nil then SysFreeString(bstrHelpFile);
  765.   end;
  766.   raise E;
  767. end;
  768.  
  769. { Call GetIDsOfNames method on the given IDispatch interface }
  770.  
  771. procedure GetIDsOfNames(Dispatch: IDispatch; Names: PChar;
  772.   NameCount: Integer; DispIDs: PDispIDList);
  773. var
  774.   I, N: Integer;
  775.   Ch: WideChar;
  776.   P: PWideChar;
  777.   NameRefs: array[0..MaxDispArgs - 1] of PWideChar;
  778.   WideNames: array[0..1023] of WideChar;
  779. begin
  780.   I := 0;
  781.   N := 0;
  782.   repeat
  783.     P := @WideNames[I];
  784.     if N = 0 then NameRefs[0] := P else NameRefs[NameCount - N] := P;
  785.     repeat
  786.       Ch := WideChar(Names[I]);
  787.       WideNames[I] := Ch;
  788.       Inc(I);
  789.     until Char(Ch) = #0;
  790.     Inc(N);
  791.   until N = NameCount;
  792.   if Dispatch.GetIDsOfNames(GUID_NULL, @NameRefs, NameCount,
  793.     LOCALE_SYSTEM_DEFAULT, DispIDs) <> 0 then
  794.     raise EOleError.CreateFmt(SNoMethod, [Names]);
  795. end;
  796.  
  797. { Central call dispatcher }
  798.  
  799. procedure VarDispInvoke(Result: PVariant; const Instance: Variant;
  800.   CallDesc: PCallDesc; Params: Pointer); cdecl;
  801. var
  802.   Dispatch: IDispatch;
  803.   DispIDs: array[0..MaxDispArgs - 1] of Integer;
  804. begin
  805.   Dispatch := VarToInterface(Instance);
  806.   GetIDsOfNames(Dispatch, @CallDesc^.ArgTypes[CallDesc^.ArgCount],
  807.     CallDesc^.NamedArgCount + 1, @DispIDs);
  808.   if Result <> nil then VarClear(Result^);
  809.   DispInvoke(Dispatch, CallDesc, @DispIDs, @Params, Result);
  810. end;
  811.  
  812. function DllGetClassObject(const CLSID: TCLSID; const IID: TIID;
  813.   var Obj): HResult;
  814. var
  815.   RegistryClass: TRegistryClass;
  816.   ClassFactory: TClassFactory;
  817. begin
  818.   RegistryClass := Automation.FRegistryList;
  819.   while RegistryClass <> nil do
  820.   begin
  821.     if IsEqualCLSID(RegistryClass.FClassID, CLSID) then
  822.     begin
  823.       try
  824.         ClassFactory := TClassFactory.Create(RegistryClass.FAutoClass);
  825.       except
  826.         Result := E_UNEXPECTED;
  827.         Exit;
  828.       end;
  829.       Result := ClassFactory.QueryInterface(IID, Obj);
  830.       ClassFactory.Release;
  831.       Exit;
  832.     end;
  833.     RegistryClass := RegistryClass.FNext;
  834.   end;
  835.   Pointer(Obj) := nil;
  836.   Result := CLASS_E_CLASSNOTAVAILABLE;
  837. end;
  838.  
  839. function DllCanUnloadNow: HResult;
  840. begin
  841.   Result := S_FALSE;
  842.   if (Automation.FAutoObjectCount = 0) and
  843.     (Automation.FClassFactoryCount = 0) then Result := S_OK;
  844. end;
  845.  
  846. function DllRegisterServer: HResult;
  847. begin
  848.   Automation.UpdateRegistry(True);
  849.   Result := S_OK;
  850. end;
  851.  
  852. function DllUnregisterServer: HResult;
  853. begin
  854.   Automation.UpdateRegistry(False);
  855.   Result := S_OK;
  856. end;
  857.  
  858. { EOleSysError }
  859.  
  860. constructor EOleSysError.Create(ErrorCode: Integer);
  861. var
  862.   Message: string;
  863. begin
  864.   Message := SysErrorMessage(ErrorCode);
  865.   if Message = '' then FmtStr(Message, SOleError, [ErrorCode]);
  866.   inherited Create(Message);
  867.   FErrorCode := ErrorCode;
  868. end;
  869.  
  870. { EOleException }
  871.  
  872. constructor EOleException.Create(const ExcepInfo: TExcepInfo);
  873. var
  874.   Message: string;
  875.   Len: Integer;
  876. begin
  877.   with ExcepInfo do
  878.   begin
  879.     if bstrDescription <> nil then
  880.     begin
  881.       WideCharToStrVar(bstrDescription, Message);
  882.       Len := Length(Message);
  883.       while (Len > 0) and (Message[Len] in [#0..#32, '.']) do Dec(Len);
  884.       SetLength(Message, Len);
  885.     end;
  886.     inherited CreateHelp(Message, dwHelpContext);
  887.     if scode <> 0 then FErrorCode := scode else FErrorCode := wCode;
  888.     if bstrSource <> nil then WideCharToStrVar(bstrSource, FSource);
  889.     if bstrHelpFile <> nil then WideCharToStrVar(bstrHelpFile, FHelpFile);
  890.   end;
  891. end;
  892.  
  893. { TAutoDispatch }
  894.  
  895. constructor TAutoDispatch.Create(AutoObject: TAutoObject);
  896. begin
  897.   FAutoObject := AutoObject;
  898. end;
  899.  
  900. function TAutoDispatch.QueryInterface(const iid: TIID; var obj): HResult;
  901. begin
  902.   Result := FAutoObject.QueryInterface(iid, obj);
  903. end;
  904.  
  905. function TAutoDispatch.AddRef: Longint;
  906. begin
  907.   Result := FAutoObject.AddRef;
  908. end;
  909.  
  910. function TAutoDispatch.Release: Longint;
  911. begin
  912.   Result := FAutoObject.Release;
  913. end;
  914.  
  915. function TAutoDispatch.GetTypeInfoCount(var ctinfo: Integer): HResult;
  916. begin
  917.   ctinfo := 0;
  918.   Result := S_OK;
  919. end;
  920.  
  921. function TAutoDispatch.GetTypeInfo(itinfo: Integer; lcid: TLCID;
  922.   var tinfo: ITypeInfo): HResult;
  923. begin
  924.   tinfo := nil;
  925.   Result := E_NOTIMPL;
  926. end;
  927.  
  928. function TAutoDispatch.GetIDsOfNames(const iid: TIID; rgszNames: POleStrList;
  929.   cNames: Integer; lcid: TLCID; rgdispid: PDispIDList): HResult;
  930. begin
  931.   Result := FAutoObject.GetIDsOfNames(rgszNames, cNames, rgdispid);
  932. end;
  933.  
  934. function TAutoDispatch.Invoke(dispIDMember: TDispID; const iid: TIID;
  935.   lcid: TLCID; flags: Word; var dispParams: TDispParams; varResult: PVariant;
  936.   excepInfo: PExcepInfo; argErr: PInteger): HResult;
  937. begin
  938.   Result := FAutoObject.Invoke(dispIDMember, flags, dispParams,
  939.     varResult, excepInfo, argErr);
  940. end;
  941.  
  942. function TAutoDispatch.GetAutoObject: TAutoObject;
  943. begin
  944.   Result := FAutoObject;
  945. end;
  946.  
  947. { TAutoObject }
  948.  
  949. constructor TAutoObject.Create;
  950. begin
  951.   Automation.CountAutoObject(True);
  952.   FRefCount := 1;
  953.   FAutoDispatch := CreateAutoDispatch;
  954. end;
  955.  
  956. destructor TAutoObject.Destroy;
  957. begin
  958.   FAutoDispatch.Free;
  959.   Automation.CountAutoObject(False);
  960. end;
  961.  
  962. function TAutoObject.AddRef: Integer;
  963. begin
  964.   Inc(FRefCount);
  965.   Result := FRefCount;
  966. end;
  967.  
  968. function TAutoObject.CreateAutoDispatch: TAutoDispatch;
  969. begin
  970.   Result := TAutoDispatch.Create(Self);
  971. end;
  972.  
  973. procedure TAutoObject.GetExceptionInfo(ExceptObject: TObject;
  974.   var ExcepInfo: TExcepInfo);
  975. begin
  976.   with ExcepInfo do
  977.   begin
  978.     bstrSource := StringToOleStr(ClassName);
  979.     if ExceptObject is Exception then
  980.       bstrDescription := StringToOleStr(Exception(ExceptObject).Message);
  981.     scode := E_FAIL;
  982.   end;
  983. end;
  984.  
  985. function TAutoObject.GetIDsOfNames(Names: POleStrList;
  986.   Count: Integer; DispIDs: PDispIDList): HResult;
  987. var
  988.   I, DispID: Integer;
  989.   Name: ShortString;
  990. begin
  991.   WideCharToShortString(Names^[0], Name);
  992.   DispID := GetDispIDOfName(ClassType, Name);
  993.   DispIDs^[0] := DispID;
  994.   if Count > 1 then
  995.     for I := 1 to Count - 1 do DispIDs^[I] := -1;
  996.   if (DispID = -1) or (Count > 1) then
  997.     Result := DISP_E_UNKNOWNNAME else
  998.     Result := S_OK;
  999. end;
  1000.  
  1001. function TAutoObject.GetOleObject: Variant;
  1002. begin
  1003.   VarClear(Result);
  1004.   TVarData(Result).VType := varDispatch;
  1005.   TVarData(Result).VDispatch := FAutoDispatch;
  1006.   AddRef;
  1007. end;
  1008.  
  1009. function TAutoObject.Invoke(DispID: TDispID; Flags: Integer;
  1010.   var Params: TDispParams; VarResult: PVariant; ExcepInfo: PExcepInfo;
  1011.   ArgErr: PInteger): HResult;
  1012. type
  1013.   TVarStrDesc = record
  1014.     PStr: Pointer;
  1015.     BStr: PBStr;
  1016.   end;
  1017. var
  1018.   AutoEntry: PAutoEntry;
  1019.   ArgCount, NamedArgCount, ArgIndex, StrCount, I, J, K: Integer;
  1020.   ParamPtr, ArgPtr: PVarData;
  1021.   ArgType, VarFlag: Byte;
  1022.   StringPtr: Pointer;
  1023.   OleStr: TBStr;
  1024.   ResVar: TVarData;
  1025.   Strings: array[0..MaxDispArgs - 1] of TVarStrDesc;
  1026.   Args: array[0..MaxDispArgs - 1] of TVarData;
  1027. begin
  1028.   if Flags = DISPATCH_PROPERTYPUTREF then Flags := DISPATCH_PROPERTYPUT;
  1029.   AutoEntry := GetAutoEntry(ClassType, DispID, Flags);
  1030.   if (AutoEntry = nil) or (AutoEntry^.Params^.ResType = 0) and
  1031.     (VarResult <> nil) then
  1032.   begin
  1033.     Result := DISP_E_MEMBERNOTFOUND;
  1034.     Exit;
  1035.   end;
  1036.   NamedArgCount := Params.cNamedArgs;
  1037.   if Flags = DISPATCH_PROPERTYPUT then Dec(NamedArgCount);
  1038.   if NamedArgCount <> 0 then
  1039.   begin
  1040.     Result := DISP_E_NONAMEDARGS;
  1041.     Exit;
  1042.   end;
  1043.   ArgCount := Params.cArgs;
  1044.   if ArgCount <> AutoEntry^.Params^.ParamCount then
  1045.   begin
  1046.     Result := DISP_E_BADPARAMCOUNT;
  1047.     Exit;
  1048.   end;
  1049.   Result := S_OK;
  1050.   StrCount := 0;
  1051.   for I := 0 to ArgCount - 1 do Args[I].VType := varEmpty;
  1052.   ResVar.VType := varEmpty;
  1053.   try
  1054.     try
  1055.       if ArgCount <> 0 then
  1056.       begin
  1057.         ParamPtr := @Params.rgvarg^[ArgCount];
  1058.         ArgPtr := @Args;
  1059.         ArgIndex := 0;
  1060.         repeat
  1061.           Dec(Integer(ParamPtr), SizeOf(Variant));
  1062.           ArgType := AutoEntry^.Params^.ParamTypes[ArgIndex] and atTypeMask;
  1063.           VarFlag := AutoEntry^.Params^.ParamTypes[ArgIndex] and atByRef;
  1064.           if (ParamPtr^.VType = varError) and ((ArgType <> varVariant) or
  1065.             (VarFlag <> 0)) then
  1066.           begin
  1067.             Result := DISP_E_PARAMNOTOPTIONAL;
  1068.             Break;
  1069.           end;
  1070.           if VarFlag <> 0 then
  1071.           begin
  1072.             if ParamPtr^.VType <> (ArgType and atVarMask or varByRef) then
  1073.             begin
  1074.               Result := DISP_E_TYPEMISMATCH;
  1075.               Break;
  1076.             end;
  1077.             if ArgType = varStrArg then
  1078.             begin
  1079.               with Strings[StrCount] do
  1080.               begin
  1081.                 PStr := nil;
  1082.                 BStr := ParamPtr^.VPointer;
  1083.                 OleStrToStrVar(BStr^, string(PStr));
  1084.                 ArgPtr^.VType := varString or varByRef;
  1085.                 ArgPtr^.VPointer := @PStr;
  1086.               end;
  1087.               Inc(StrCount);
  1088.             end else
  1089.             begin
  1090.               ArgPtr^.VType := ParamPtr^.VType;
  1091.               ArgPtr^.VPointer := ParamPtr^.VPointer;
  1092.             end;
  1093.           end else
  1094.           if ArgType = varVariant then
  1095.           begin
  1096.             ArgPtr^.VType := varVariant or varByRef;
  1097.             ArgPtr^.VPointer := ParamPtr;
  1098.           end else
  1099.           begin
  1100.             Result := VariantChangeTypeEx(PVariant(ArgPtr)^,
  1101.               PVariant(ParamPtr)^, LOCALE_USER_DEFAULT, 0,
  1102.               ArgType and atVarMask);
  1103.             if Result <> S_OK then Break;
  1104.             if ArgType = varStrArg then
  1105.             begin
  1106.               StringPtr := nil;
  1107.               OleStrToStrVar(ArgPtr^.VOleStr, string(StringPtr));
  1108.               VariantClear(PVariant(ArgPtr)^);
  1109.               ArgPtr^.VType := varString;
  1110.               ArgPtr^.VString := StringPtr;
  1111.             end;
  1112.           end;
  1113.           Inc(Integer(ArgPtr), SizeOf(Variant));
  1114.           Inc(ArgIndex);
  1115.         until ArgIndex = ArgCount;
  1116.         if Result <> S_OK then
  1117.         begin
  1118.           if ArgErr <> nil then ArgErr^ := ArgCount - ArgIndex - 1;
  1119.           Exit;
  1120.         end;
  1121.       end;
  1122.       InvokeMethod(AutoEntry, @Args, @ResVar);
  1123.       for J := 0 to StrCount - 1 do
  1124.         with Strings[J] do
  1125.         begin
  1126.           OleStr := StringToOleStr(string(PStr));
  1127.           SysFreeString(BStr^);
  1128.           BStr^ := OleStr;
  1129.         end;
  1130.       if VarResult <> nil then
  1131.         if ResVar.VType = varString then
  1132.         begin
  1133.           OleStr := StringToOleStr(string(ResVar.VString));
  1134.           VariantClear(VarResult^);
  1135.           PVarData(VarResult)^.VType := varOleStr;
  1136.           PVarData(VarResult)^.VOleStr := OleStr;
  1137.         end else
  1138.         begin
  1139.           VariantClear(VarResult^);
  1140.           Move(ResVar, VarResult^, SizeOf(Variant));
  1141.           ResVar.VType := varEmpty;
  1142.         end;
  1143.     finally
  1144.       for K := 0 to StrCount - 1 do string(Strings[K].PStr) := '';
  1145.       for K := 0 to ArgCount - 1 do VarClear(Variant(Args[K]));
  1146.       VarClear(Variant(ResVar));
  1147.     end;
  1148.   except
  1149.     if ExcepInfo <> nil then
  1150.     begin
  1151.       FillChar(ExcepInfo^, SizeOf(TExcepInfo), 0);
  1152.       GetExceptionInfo(ExceptObject, ExcepInfo^);
  1153.     end;
  1154.     Result := DISP_E_EXCEPTION;
  1155.   end;
  1156. end;
  1157.  
  1158. procedure TAutoObject.InvokeMethod(AutoEntry, Args, Result: Pointer);
  1159. var
  1160.   Instance, AutoData: Pointer;
  1161. asm
  1162.         PUSH    EBX
  1163.         PUSH    ESI
  1164.         PUSH    EDI
  1165.         MOV     Instance,EAX
  1166.         MOV     EBX,EDX
  1167.         MOV     ESI,[EBX].TAutoEntry.Params
  1168.         MOV     EDI,-2
  1169.         MOVZX   EAX,[ESI].TParamList.ParamCount
  1170.         OR      EAX,EAX
  1171.         JE      @CheckResult
  1172.         MOV     AutoData,EBX
  1173.         MOV     EBX,EAX
  1174.         MOV     ESI,ECX
  1175.  
  1176. @PushLoop:
  1177.         MOV     AX,[ESI].Word[0]
  1178.         CMP     EAX,varSingle
  1179.         JE      @Push4
  1180.         CMP     EAX,varDouble
  1181.         JE      @Push8
  1182.         CMP     EAX,varCurrency
  1183.         JE      @Push8
  1184.         CMP     EAX,varDate
  1185.         JE      @Push8
  1186.         INC     EDI
  1187.         JG      @Push4
  1188.         JE      @LoadECX
  1189.  
  1190. @LoadEDX:
  1191.         MOV     EDX,[ESI].Integer[8]
  1192.         JMP     @PushNext
  1193.  
  1194. @LoadECX:
  1195.         MOV     ECX,[ESI].Integer[8]
  1196.         JMP     @PushNext
  1197.  
  1198. @Push8:
  1199.         PUSH    [ESI].Integer[12]
  1200.  
  1201. @Push4:
  1202.         PUSH    [ESI].Integer[8]
  1203.  
  1204. @PushNext:
  1205.         ADD     ESI,16
  1206.         DEC     EBX
  1207.         JNE     @PushLoop
  1208.         MOV     EBX,AutoData
  1209.         MOV     ESI,[EBX].TAutoEntry.Params
  1210.  
  1211. @CheckResult:
  1212.         MOV     AL,[ESI].TParamList.ResType
  1213.         CMP     AL,varOleStr
  1214.         JE      @PassOleStrRes
  1215.         CMP     AL,varStrArg
  1216.         JE      @PassStringRes
  1217.         CMP     AL,varVariant
  1218.         JNE     @Invoke
  1219.  
  1220. @PassVarRes:
  1221.         MOV     EAX,Result
  1222.         JMP     @PassResult
  1223.  
  1224. @PassOleStrRes:
  1225.         MOV     EAX,Result
  1226.         MOV     [EAX].Word,varOleStr
  1227.         JMP     @PassStrRes
  1228.  
  1229. @PassStringRes:
  1230.         MOV     EAX,Result
  1231.         MOV     [EAX].Word,varString
  1232.  
  1233. @PassStrRes:
  1234.         ADD     EAX,8
  1235.         MOV     [EAX].Integer,0
  1236.  
  1237. @PassResult:
  1238.         INC     EDI
  1239.         JG      @ResultPush
  1240.         JE      @ResultECX
  1241.  
  1242. @ResultEDX:
  1243.         MOV     EDX,EAX
  1244.         JMP     @Invoke
  1245.  
  1246. @ResultECX:
  1247.         MOV     ECX,EAX
  1248.         JMP     @Invoke
  1249.  
  1250. @ResultPush:
  1251.         PUSH    EAX
  1252.  
  1253. @Invoke:
  1254.         MOV     EAX,Instance
  1255.         LEA     EDI,[EBX].TAutoEntry.Address
  1256.         TEST    [EBX].TAutoEntry.Flags,afVirtual
  1257.         JE      @CallMethod
  1258.         MOV     EDI,[EAX]
  1259.         ADD     EDI,[EBX].TAutoEntry.Address
  1260.  
  1261. @CallMethod:
  1262.         CALL    [EDI].Pointer
  1263.         MOV     EDX,Result
  1264.         MOV     CL,[ESI].TParamList.ResType
  1265.         AND     ECX,atVarMask
  1266.         JMP     @ResultTable.Pointer[ECX*4]
  1267.  
  1268. @ResultTable:
  1269.         DD      @ResNone
  1270.         DD      @ResNone
  1271.         DD      @ResInteger
  1272.         DD      @ResInteger
  1273.         DD      @ResSingle
  1274.         DD      @ResDouble
  1275.         DD      @ResCurrency
  1276.         DD      @ResDouble
  1277.         DD      @ResNone
  1278.         DD      @ResNone
  1279.         DD      @ResNone
  1280.         DD      @ResInteger
  1281.         DD      @ResNone
  1282.  
  1283. @ResSingle:
  1284.         FSTP    [EDX].Single[8]
  1285.         FWAIT
  1286.         JMP     @ResSetType
  1287.  
  1288. @ResDouble:
  1289.         FSTP    [EDX].Double[8]
  1290.         FWAIT
  1291.         JMP     @ResSetType
  1292.  
  1293. @ResCurrency:
  1294.         FISTP   [EDX].Currency[8]
  1295.         FWAIT
  1296.         JMP     @ResSetType
  1297.  
  1298. @ResInteger:
  1299.         MOV     [EDX].Integer[8],EAX
  1300.  
  1301. @ResSetType:
  1302.         MOV     [EDX].Word,CX
  1303.  
  1304. @ResNone:
  1305.         POP     EDI
  1306.         POP     ESI
  1307.         POP     EBX
  1308. end;
  1309.  
  1310. function TAutoObject.QueryInterface(const iid: TIID; var obj): HResult;
  1311. begin
  1312.   if IsEqualIID(iid, IID_IUnknown) or IsEqualIID(iid, IID_IDispatch) or
  1313.     IsEqualIID(iid, IID_IAutoDispatch) then
  1314.   begin
  1315.     Pointer(obj) := FAutoDispatch;
  1316.     AddRef;
  1317.     Result := S_OK;
  1318.   end else
  1319.   begin
  1320.     Pointer(obj) := nil;
  1321.     Result := E_NOINTERFACE;
  1322.   end;
  1323. end;
  1324.  
  1325. function TAutoObject.Release: Integer;
  1326. begin
  1327.   Dec(FRefCount);
  1328.   Result := FRefCount;
  1329.   if FRefCount = 0 then Free;
  1330. end;
  1331.  
  1332. { TClassFactory }
  1333.  
  1334. constructor TClassFactory.Create(AutoClass: TAutoClass);
  1335. begin
  1336.   Inc(Automation.FClassFactoryCount);
  1337.   FRefCount := 1;
  1338.   FAutoClass := AutoClass;
  1339. end;
  1340.  
  1341. destructor TClassFactory.Destroy;
  1342. begin
  1343.   Dec(Automation.FClassFactoryCount);
  1344. end;
  1345.  
  1346. function TClassFactory.QueryInterface(const iid: TIID; var obj): HResult;
  1347. begin
  1348.   if IsEqualIID(iid, IID_IUnknown) or IsEqualIID(iid, IID_IClassFactory) then
  1349.   begin
  1350.     Pointer(obj) := Self;
  1351.     AddRef;
  1352.     Result := S_OK;
  1353.   end else
  1354.   begin
  1355.     Pointer(obj) := nil;
  1356.     Result := E_NOINTERFACE;
  1357.   end;
  1358. end;
  1359.  
  1360. function TClassFactory.AddRef: Longint;
  1361. begin
  1362.   Inc(FRefCount);
  1363.   Result := FRefCount;
  1364. end;
  1365.  
  1366. function TClassFactory.Release: Longint;
  1367. begin
  1368.   Dec(FRefCount);
  1369.   Result := FRefCount;
  1370.   if FRefCount = 0 then Free;
  1371. end;
  1372.  
  1373. function TClassFactory.CreateInstance(unkOuter: IUnknown; const iid: TIID;
  1374.   var obj): HResult;
  1375. var
  1376.   AutoObject: TAutoObject;
  1377. begin
  1378.   Pointer(obj) := nil;
  1379.   if unkOuter <> nil then
  1380.   begin
  1381.     Result := CLASS_E_NOAGGREGATION;
  1382.     Exit;
  1383.   end;
  1384.   try
  1385.     AutoObject := FAutoClass.Create;
  1386.   except
  1387.     Result := E_UNEXPECTED;
  1388.     Exit;
  1389.   end;
  1390.   Result := AutoObject.QueryInterface(iid, obj);
  1391.   AutoObject.Release;
  1392. end;
  1393.  
  1394. function TClassFactory.LockServer(fLock: BOOL): HResult;
  1395. begin
  1396.   Automation.CountAutoObject(fLock);
  1397.   Result := S_OK;
  1398. end;
  1399.  
  1400. { TRegistryClass }
  1401.  
  1402. constructor TRegistryClass.Create(const AutoClassInfo: TAutoClassInfo);
  1403. const
  1404.   RegFlags: array[acSingleInstance..acMultiInstance] of Integer = (
  1405.     REGCLS_SINGLEUSE, REGCLS_MULTIPLEUSE);
  1406. var
  1407.   ClassFactory: TClassFactory;
  1408. begin
  1409.   FAutoClass := AutoClassInfo.AutoClass;
  1410.   FProgID := AutoClassInfo.ProgID;
  1411.   FClassID := StringToClassID(AutoClassInfo.ClassID);
  1412.   FDescription := AutoClassInfo.Description;
  1413.   FInstancing := AutoClassInfo.Instancing;
  1414.   if not Automation.IsInprocServer and (FInstancing <> acInternal) then
  1415.   begin
  1416.     ClassFactory := TClassFactory.Create(FAutoClass);
  1417.     CoRegisterClassObject(FClassID, ClassFactory, CLSCTX_LOCAL_SERVER,
  1418.       RegFlags[FInstancing], FRegister);
  1419.     ClassFactory.Release;
  1420.   end;
  1421. end;
  1422.  
  1423. destructor TRegistryClass.Destroy;
  1424. begin
  1425.   if FRegister <> 0 then CoRevokeClassObject(FRegister);
  1426. end;
  1427.  
  1428. procedure TRegistryClass.UpdateRegistry(Register: Boolean);
  1429. var
  1430.   ClassID, FileName: string;
  1431.   Buffer: array[0..261] of Char;
  1432. begin
  1433.   if FInstancing <> acInternal then
  1434.   begin
  1435.     ClassID := ClassIDToString(FClassID);
  1436.     SetString(FileName, Buffer, GetModuleFileName(HInstance, Buffer,
  1437.       SizeOf(Buffer)));
  1438.     if Register then
  1439.     begin
  1440.       CreateRegKey(FProgID, FDescription);
  1441.       CreateRegKey(FProgID + '\Clsid', ClassID);
  1442.       CreateRegKey('CLSID\' + ClassID, FDescription);
  1443.       CreateRegKey('CLSID\' + ClassID + '\ProgID', FProgID);
  1444.       CreateRegKey('CLSID\' + ClassID + '\' + GetServerKey, FileName);
  1445.     end else
  1446.     begin
  1447.       DeleteRegKey('CLSID\' + ClassID + '\' + GetServerKey);
  1448.       DeleteRegKey('CLSID\' + ClassID + '\ProgID');
  1449.       DeleteRegKey('CLSID\' + ClassID);
  1450.       DeleteRegKey(FProgID + '\Clsid');
  1451.       DeleteRegKey(FProgID);
  1452.     end;
  1453.   end;
  1454. end;
  1455.  
  1456. { TAutomation }
  1457.  
  1458. var
  1459.   SaveInitProc: Pointer;
  1460.  
  1461. procedure InitAutomation;
  1462. begin
  1463.   if SaveInitProc <> nil then TProcedure(SaveInitProc);
  1464.   Automation.Initialize;
  1465. end;
  1466.  
  1467. constructor TAutomation.Create;
  1468. begin
  1469.   FIsInprocServer := IsLibrary;
  1470.   if FindCmdLineSwitch('AUTOMATION') or FindCmdLineSwitch('EMBEDDING') then
  1471.     FStartMode := smAutomation
  1472.   else if FindCmdLineSwitch('REGSERVER') then
  1473.     FStartMode := smRegServer
  1474.   else if FindCmdLineSwitch('UNREGSERVER') then
  1475.     FStartMode := smUnregServer;
  1476. end;
  1477.  
  1478. destructor TAutomation.Destroy;
  1479. var
  1480.   RegistryClass: TRegistryClass;
  1481. begin
  1482.   while FRegistryList <> nil do
  1483.   begin
  1484.     RegistryClass := FRegistryList;
  1485.     FRegistryList := RegistryClass.FNext;
  1486.     RegistryClass.Free;
  1487.   end;
  1488. end;
  1489.  
  1490. procedure TAutomation.CountAutoObject(Created: Boolean);
  1491. begin
  1492.   if Created then Inc(FAutoObjectCount) else
  1493.   begin
  1494.     Dec(FAutoObjectCount);
  1495.     if FAutoObjectCount = 0 then LastReleased;
  1496.   end;
  1497. end;
  1498.  
  1499. procedure TAutomation.Initialize;
  1500. begin
  1501.   UpdateRegistry(FStartMode <> smUnregServer);
  1502.   if FStartMode in [smRegServer, smUnregServer] then Halt;
  1503. end;
  1504.  
  1505. procedure TAutomation.LastReleased;
  1506. var
  1507.   Shutdown: Boolean;
  1508. begin
  1509.   if not FIsInprocServer then
  1510.   begin
  1511.     Shutdown := FStartMode = smAutomation;
  1512.     if Assigned(FOnLastRelease) then FOnLastRelease(Shutdown);
  1513.     if Shutdown then PostQuitMessage(0);
  1514.   end;
  1515. end;
  1516.  
  1517. procedure TAutomation.RegisterClass(const AutoClassInfo: TAutoClassInfo);
  1518. var
  1519.   RegistryClass: TRegistryClass;
  1520. begin
  1521.   RegistryClass := TRegistryClass.Create(AutoClassInfo);
  1522.   RegistryClass.FNext := FRegistryList;
  1523.   FRegistryList := RegistryClass;
  1524. end;
  1525.  
  1526. procedure TAutomation.UpdateRegistry(Register: Boolean);
  1527. var
  1528.   RegistryClass: TRegistryClass;
  1529. begin
  1530.   RegistryClass := FRegistryList;
  1531.   while RegistryClass <> nil do
  1532.   begin
  1533.     RegistryClass.UpdateRegistry(Register);
  1534.     RegistryClass := RegistryClass.FNext;
  1535.   end;
  1536. end;
  1537.  
  1538. initialization
  1539. begin
  1540.   OleInitialize(nil);
  1541.   Automation := TAutomation.Create;
  1542.   SaveInitProc := InitProc;
  1543.   InitProc := @InitAutomation;
  1544. end;
  1545.  
  1546. finalization
  1547. begin
  1548.   Automation.Free;
  1549.   OleUninitialize;
  1550. end;
  1551.  
  1552. end.
  1553.