home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Vcl / oleserver.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  11KB  |  333 lines

  1. {*******************************************************}
  2. {       Borland Delphi Visual Component Library         }
  3. {       Support classes for hosting servers in IDE      }
  4. {                                                       }
  5. {       $Revision:   1.19  $                            }
  6. {       Copyright (c) 1999 Inprise Corporation          }
  7. {*******************************************************}
  8. unit OleServer;
  9.  
  10. {$R-}
  11.  
  12. interface
  13.  
  14. uses Windows, Messages, ActiveX, SysUtils, Classes, ComObj;
  15.  
  16. type
  17.   TVariantArray = Array of OleVariant;
  18.   TOleServer    = class;
  19.   TConnectKind  = (ckRunningOrNew,          // Attach to a running or create a new instance of the server
  20.                    ckNewInstance,           // Create a new instance of the server
  21.                    ckRunningInstance,       // Attach to a running instance of the server
  22.                    ckRemote,                // Bind to a remote instance of the server
  23.                    ckAttachToInterface);    // Don't bind to server, user will provide interface via 'CpnnectTo'
  24.  
  25.   TServerEventDispatch = class(TObject, IUnknown, IDispatch)
  26.   private
  27.     FServer: TOleServer;
  28.     InternalRefCount : Integer;
  29.   protected
  30.     { IUnknown }
  31.     function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  32.     function _AddRef: Integer; stdcall;
  33.     function _Release: Integer; stdcall;
  34.     { IDispatch }
  35.     function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  36.     function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  37.     function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  38.       NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  39.     function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  40.       Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  41.     property Server: TOleServer read FServer;
  42.     function ServerDisconnect :Boolean;
  43.   public
  44.     constructor Create(Server: TOleServer);
  45.   end;
  46.  
  47.   PServerData = ^TServerData;
  48.   TServerData = record
  49.     ClassID: TGUID;                   // CLSID of CoClass
  50.     IntfIID: TGUID;                   // IID of default interface
  51.     EventIID: TGUID;                  // IID of default source interface
  52.     LicenseKey: Pointer;              // Pointer to license string (not implemented)
  53.     Version: Integer;                 // Version of this structure
  54.     InstanceCount: Integer;           // Instance of the Server running
  55.   end;
  56.  
  57.   TOleServer = class(TComponent, IUnknown)
  58.   private
  59.     FServerData:        PServerData;
  60.     FRefCount:          Longint;
  61.     FEventDispatch:     TServerEventDispatch;
  62.     FEventsConnection:  Longint;
  63.     FAutoConnect:       Boolean;
  64.     FRemoteMachineName: string;
  65.     FConnectKind:       TConnectKind;
  66.  
  67.   protected
  68.       { IUnknown }
  69.     function QueryInterface(const IID: TGUID; out Obj): HResult; override;
  70.     function _AddRef: Integer; stdcall;
  71.     function _Release: Integer; stdcall;
  72.  
  73.     procedure Loaded; override;
  74.     procedure InitServerData; virtual; abstract;
  75.  
  76.     function  GetServer: IUnknown; virtual;
  77.  
  78.     procedure ConnectEvents(const Obj: IUnknown);
  79.     procedure DisconnectEvents(const Obj: Iunknown);
  80.     procedure InvokeEvent(DispID: TDispID; var Params: TVariantArray); virtual;
  81.  
  82.     function  GetConnectKind: TConnectKind;
  83.     procedure SetConnectKind(ck: TConnectKind);
  84.  
  85.     function  GetAutoConnect: Boolean;
  86.     procedure SetAutoConnect(flag: Boolean);
  87.  
  88.     property  ServerData: PServerData read FServerData write FServerData;
  89.     property  EventDispatch: TServerEventDispatch read FEventDispatch write FEventDispatch;
  90.  
  91.   public
  92.     constructor Create(AOwner: TComponent); override;
  93.     destructor Destroy; override;
  94.  
  95.     // NOTE: If derived class is generated by TLIBIMP or ImportTypeLibraryCodeGenerator,
  96.     //       the derived class will also expose a 'ConnectTo(interface)' function.
  97.     //       You must invoke that method if you're using 'ckAttachToInterface' connection
  98.     //       kind.
  99.     procedure Connect; virtual; abstract;
  100.     procedure Disconnect; virtual; abstract;
  101.  
  102.   published
  103.     property AutoConnect: Boolean read GetAutoConnect write SetAutoConnect;
  104.     property ConnectKind: TConnectKind read GetConnectKind write SetConnectKind;
  105.     property RemoteMachineName: string read FRemoteMachineName write FRemoteMachineName;
  106.   end;
  107.  
  108.  
  109. implementation
  110.  
  111. uses OleConst;
  112.  
  113. { TServerEventDispatch }
  114. constructor TServerEventDispatch.Create(Server: TOleServer);
  115. begin
  116.   FServer := Server;
  117.   InternalRefCount := 1;
  118. end;
  119.  
  120. { TServerEventDispatch.IUnknown }
  121. function TServerEventDispatch.QueryInterface(const IID: TGUID; out Obj): HResult;
  122. begin
  123.   if GetInterface(IID, Obj) then
  124.   begin
  125.     Result := S_OK;
  126.     Exit;
  127.   end;
  128.   if IsEqualIID(IID, FServer.FServerData^.EventIID) then
  129.   begin
  130.     GetInterface(IDispatch, Obj);
  131.     Result := S_OK;
  132.     Exit;
  133.   end;
  134.   Result := E_NOINTERFACE;
  135. end;
  136.  
  137. function TServerEventDispatch._AddRef: Integer;
  138. begin
  139.   if FServer <> nil then FServer._AddRef;
  140.   InternalRefCount := InternalRefCount + 1;
  141.   Result := InternalRefCount;
  142. end;
  143.  
  144. function TServerEventDispatch._Release: Integer;
  145. begin
  146.   if FServer <> nil then FServer._Release;
  147.   InternalRefCount := InternalRefCount -1;
  148.   Result := InternalRefCount;
  149. end;
  150.  
  151. { TServerEventDispatch.IDispatch }
  152. function TServerEventDispatch.GetTypeInfoCount(out Count: Integer): HResult;
  153. begin
  154.   Count := 0;
  155.   Result:= S_OK;
  156. end;
  157.  
  158. function TServerEventDispatch.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult;
  159. begin
  160.   Pointer(TypeInfo) := nil;
  161.   Result := E_NOTIMPL;
  162. end;
  163.  
  164. function TServerEventDispatch.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  165.   NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
  166. begin
  167.   Result := E_NOTIMPL;
  168. end;
  169.  
  170. function TServerEventDispatch.Invoke(DispID: Integer; const IID: TGUID;
  171.   LocaleID: Integer; Flags: Word; var Params;
  172.   VarResult, ExcepInfo, ArgErr: Pointer): HResult;
  173. var
  174.   ParamCount, I: integer;
  175.   VarArray : TVariantArray;
  176. begin
  177.   // Get parameter count
  178.   ParamCount := TDispParams(Params).cArgs;
  179.   // Set our array to appropriate length
  180.   SetLength(VarArray, ParamCount);
  181.   // Copy over data
  182.   for I := Low(VarArray) to High(VarArray) do
  183.     VarArray[High(VarArray)-I] := OleVariant(TDispParams(Params).rgvarg^[I]);
  184.   // Invoke Server proxy class
  185.   if FServer <> nil then FServer.InvokeEvent(DispID, VarArray);
  186.   // Clean array
  187.   SetLength(VarArray, 0);
  188.   // Pascal Events return 'void' - so assume success!
  189.   Result := S_OK;
  190. end;
  191.  
  192. function TServerEventDispatch.ServerDisconnect : Boolean;
  193. begin
  194.   FServer := nil;
  195.   if FServer <> nil then
  196.     Result := false
  197.   else Result := true;
  198. end;
  199.  
  200. {TOleServer}
  201. constructor TOleServer.Create(AOwner: TComponent);
  202. begin
  203.   inherited Create(AOwner);
  204.   // Allow derived class to initialize ServerData structure pointer
  205.   InitServerData;
  206.   // Make sure derived class set ServerData pointer to some valid structure
  207.   Assert(FServerData <> nil);
  208.   // Increment instance count (not used currently)
  209.   Inc(FServerData^.InstanceCount);
  210.   // Create Event Dispatch Handler
  211.   FEventDispatch := TServerEventDispatch.Create(Self);
  212. end;
  213.  
  214. destructor TOleServer.Destroy;
  215. begin
  216.   // Disconnect from the Server (NOTE: Disconnect must handle case when we're no longer connected)
  217.   Disconnect;
  218.   // Free Events dispatcher
  219.   FEventDispatch.ServerDisconnect;
  220.   if (FEventDispatch._Release = 0) then FEventDispatch.Free;
  221.   // Decrement refcount
  222.   Dec(FServerData^.InstanceCount);
  223.   inherited Destroy;
  224. end;
  225.  
  226. procedure TOleServer.Loaded;
  227. begin
  228.   inherited Loaded;
  229.  
  230.   // Load Server if user requested 'AutoConnect' and we're not in Design mode
  231.   if not (csDesigning in ComponentState) then
  232.     if AutoConnect then
  233.         Connect;
  234. end;
  235.  
  236. procedure TOleServer.InvokeEvent(DispID: TDispID; var Params: TVariantArray);
  237. begin
  238.   // To be overriden in derived classes to do dispatching
  239. end;
  240.  
  241. function TOleServer.GetServer: IUnknown;
  242. var
  243.   HR: HResult;
  244.   ErrorStr: string;
  245. begin
  246.   case ConnectKind of
  247.     ckNewInstance:
  248.       Result := CreateComObject(FServerData^.ClassId);
  249.  
  250.     ckRunningInstance:
  251.     begin
  252.       HR := GetActiveObject(FServerData^.ClassId, nil, Result);
  253.       if not Succeeded(HR) then
  254.       begin
  255.         ErrorStr := Format(sNoRunningObject, [ClassIDToProgID(FServerData^.ClassId),
  256.                                               GuidToString(FServerData^.ClassId)]);
  257.         raise EOleSysError.Create(ErrorStr, HR, 0);
  258.       end;
  259.     end;
  260.  
  261.     ckRunningOrNew:
  262.       if not Succeeded(GetActiveObject(FServerData^.ClassId, nil, Result)) then
  263.         Result := CreateComObject(FServerData^.ClassId);
  264.  
  265.     ckRemote:
  266.       {Highly inefficient: requires at least two round trips - GetClassObject + QI}
  267.       Result := CreateRemoteComObject(RemoteMachineName, FServerData^.ClassID);
  268.   end;
  269. end;
  270.  
  271. procedure TOleServer.ConnectEvents(const Obj: IUnknown);
  272. begin
  273.   ComObj.InterfaceConnect(Obj, FServerData^.EventIID, FEventDispatch, FEventsConnection);
  274. end;
  275.  
  276. procedure TOleServer.DisconnectEvents(const Obj: Iunknown);
  277. begin
  278.   ComObj.InterfaceDisconnect(Obj, FServerData^.EventIID, FEventsConnection);
  279. end;
  280.  
  281. function  TOleServer.GetConnectKind: TConnectKind;
  282. begin
  283.   // Should the setting of a RemoteMachine name override the Connection Kind ??
  284.   if RemoteMachineName <> '' then
  285.     Result := ckRemote
  286.   else
  287.     Result := FConnectKind;
  288. end;
  289.  
  290. procedure TOleServer.SetConnectKind(cK: TConnectKind);
  291. begin
  292.   // Should we validate that we have a RemoteMachineName for ckRemote ??
  293.   FConnectKind := cK;
  294. end;
  295.  
  296. function  TOleServer.GetAutoConnect: Boolean;
  297. begin
  298.   // If user wants to provide the interface to connect to, then we won't
  299.   // 'automatically' connect to a server.
  300.   if ConnectKind = ckAttachToInterface then
  301.     Result := False
  302.   else
  303.     Result := FAutoConnect;
  304. end;
  305.  
  306. procedure TOleServer.SetAutoConnect(flag: Boolean);
  307. begin
  308.   FAutoConnect := flag;
  309. end;
  310.  
  311. { TOleServer.IUnknown }
  312. function TOleServer.QueryInterface(const IID: TGUID; out Obj): HResult;
  313. begin
  314.   if GetInterface(IID, Obj) then
  315.     Result := S_OK
  316.   else
  317.     Result := E_NOINTERFACE;
  318. end;
  319.  
  320. function TOleServer._AddRef: Integer;
  321. begin
  322.   Inc(FRefCount);
  323.   Result := FRefCount;
  324. end;
  325.  
  326. function TOleServer._Release: Integer;
  327. begin
  328.   Dec(FRefCount);
  329.   Result := FRefCount;
  330. end;
  331.  
  332. end.
  333.