home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 April / Chip_1997-04_cd.bin / prezent / cb / data.z / OLEAUTO.PAS < prev    next >
Pascal/Delphi Source File  |  1997-01-16  |  42KB  |  1,537 lines

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