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

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {       Connection classes                              }
  6. {                                                       }
  7. {       Copyright (c) 1999 Inprise Corporation          }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit CorbaCon;
  12.  
  13. {$T-,H+,X+}
  14.  
  15. interface
  16.  
  17. uses
  18.   Messages, Windows, SysUtils, CorbaObj, CorbaStd, Classes, Midas, DBClient;
  19.  
  20. type
  21.  
  22.   { TCorbaConnection }
  23.  
  24.   TRepositoryId = type string;
  25.   TCancelEvent = procedure (Sender: TObject; var Cancel: Boolean;
  26.     var DialogMessage: string) of object;
  27.  
  28.   TCorbaConnection = class(TCustomRemoteServer)
  29.   private
  30.     FRepositoryId: TRepositoryId;
  31.     FObjectName: string;
  32.     FHostName: string;
  33.     FAppServer: Variant;
  34.     FOnCancel: TCancelEvent;
  35.     FConnecting: Boolean;
  36.     FCancelable: Boolean;
  37.     procedure ThreadTimeout(var DialogMessage: string; var Cancel: Boolean);
  38.     procedure SetRepositoryId(const Value: TRepositoryId);
  39.     procedure SetObjectName(const Value: string);
  40.     procedure SetHostName(const Value: string);
  41.   protected
  42.     function GetAppServer: Variant; virtual;
  43.     procedure SetAppServer(Value: Variant); virtual;
  44.     procedure DoConnect; override;
  45.     procedure DoDisconnect; override;
  46.     function GetConnected: Boolean; override;
  47.     procedure SetConnected(Value: Boolean); override;
  48.     procedure GetProviderNames(Proc: TGetStrProc); override;
  49.   public
  50.     constructor Create(AOwner: TComponent); override;
  51.     function GetServer: IAppServer; override;
  52.     property AppServer: Variant read GetAppServer;
  53.   published
  54.     property Cancelable: Boolean read FCancelable write FCancelable default False;
  55.     property Connected;
  56.     property RepositoryId: TRepositoryId read FRepositoryId write SetRepositoryId;
  57.     property ObjectName: string read FObjectName write SetObjectName;
  58.     property HostName: string read FHostName write SetHostName;
  59.     property AfterConnect;
  60.     property AfterDisconnect;
  61.     property BeforeConnect;
  62.     property BeforeDisconnect;
  63.     property OnCancel: TCancelEvent read FOnCancel write FOnCancel;
  64.   end;
  65.  
  66.  
  67. implementation
  68.  
  69. uses
  70.   ActiveX, ComObj, Forms, Registry, MidConst, DBLogDlg, OrbPas, Dialogs, CorbCnst;
  71.  
  72.  
  73. { TCorbaBindThread }
  74.  
  75. type
  76.   PIObject = ^IObject;
  77.   TCorbaBindThread = class(TThread)
  78.   private
  79.     FRepId: string;
  80.     FFactoryId: string;
  81.     FInstanceName: string;
  82.     FHostName: string;
  83.     FIID: TGUID;
  84.     FObjectPtr: PIObject;
  85.     FLock: TRTLCriticalSection;
  86.     FCanFree: THandle;
  87.     FCallComplete: THandle;
  88.     FException: TObject;
  89.     FFinished: Boolean;
  90.     FDialogHandle: HWND;
  91.     procedure SetDialogHandle(const Value: HWND);
  92.   public
  93.     constructor Create(const RepId, FactoryId, InstanceName, HostName: string;
  94.       IID: TGUID; var Obj: IObject);
  95.     destructor Destroy; override;
  96.     procedure Cancel;
  97.     procedure Execute; override;
  98.     procedure MarkFreeable;
  99.     property CallCompleteEvent: THandle read FCallComplete;
  100.     property Exception: TObject read FException write FException;
  101.     property Finished: Boolean read FFinished;
  102.     property DialogHandle: HWND read FDialogHandle write SetDialogHandle;
  103.   end;
  104.  
  105. { TCorbaBindThread }
  106.  
  107. constructor TCorbaBindThread.Create(const RepId, FactoryId,
  108.   InstanceName, HostName: string; IID: TGUID; var Obj: IObject);
  109. begin
  110.   FRepId := RepId;
  111.   FFactoryId := FactoryId;
  112.   FInstanceName := InstanceName;
  113.   FHostName := HostName;
  114.   FIID := IID;
  115.   FObjectPtr := @Obj;
  116.   FreeOnTerminate := True;
  117.   InitializeCriticalSection(FLock);
  118.   FCanFree := CreateEvent(nil, True, False, nil);
  119.   FCallComplete := CreateEvent(nil, True, False, nil);
  120.   inherited Create(False);
  121. end;
  122.  
  123. destructor TCorbaBindThread.Destroy;
  124. begin
  125.   DeleteCriticalSection(FLock);
  126.   CloseHandle(FCanFree);
  127.   CloseHandle(FCallComplete);
  128.   FException.Free;
  129.   inherited Destroy;
  130. end;
  131.  
  132. procedure TCorbaBindThread.Cancel;
  133. begin
  134.   EnterCriticalSection(FLock);
  135.   try
  136.     FObjectPtr := nil;
  137.     FDialogHandle := 0;
  138.   finally
  139.     LeaveCriticalSection(FLock);
  140.   end;
  141. end;
  142.  
  143. type
  144.   PRaiseFrame = ^TRaiseFrame;
  145.   TRaiseFrame = record
  146.     NextRaise: PRaiseFrame;
  147.     ExceptAddr: Pointer;
  148.     ExceptObject: TObject;
  149.     ExceptionRecord: PExceptionRecord;
  150.   end;
  151.  
  152. procedure TCorbaBindThread.Execute;
  153. var
  154.   Obj: IObject;
  155. begin
  156.   FException:= nil;
  157.   try
  158.     Obj := CORBAFactoryCreateStub(FRepID, FFactoryID,
  159.       FInstanceName, FHostName, FIID);
  160.     EnterCriticalSection(FLock);
  161.     try
  162.       if FObjectPtr <> nil then FObjectPtr^ := Obj;
  163.     finally
  164.       LeaveCriticalSection(FLock);
  165.     end;
  166.   except
  167.     if RaiseList <> nil then
  168.     begin
  169.       FException := PRaiseFrame(RaiseList)^.ExceptObject;
  170.       PRaiseFrame(RaiseList)^.ExceptObject := nil;
  171.     end;
  172.   end;
  173.   EnterCriticalSection(FLock);
  174.   try
  175.     if FDialogHandle <> 0 then PostMessage(FDialogHandle, WM_CLOSE, 0, 0);
  176.   finally
  177.     LeaveCriticalSection(FLock);
  178.   end;
  179.   FFinished := True;
  180.   ResetEvent(FCallComplete);
  181.   WaitForSingleObject(FCanFree, INFINITE);
  182. end;
  183.  
  184. procedure TCorbaBindThread.MarkFreeable;
  185. begin
  186.   ResetEvent(FCanFree);
  187. end;
  188.  
  189. procedure TCorbaBindThread.SetDialogHandle(const Value: HWND);
  190. begin
  191.   EnterCriticalSection(FLock);
  192.   try
  193.    FDialogHandle := Value;
  194.   finally
  195.     LeaveCriticalSection(FLock);
  196.   end;
  197. end;
  198.  
  199. type
  200.   TTimedOutEvent = procedure (var Msg: string; var Cancel: Boolean) of object;
  201.  
  202. function ThreadedBind(const RepId, FactoryId, InstanceName, HostName: string;
  203.   IID: TGUID; Timeout: DWORD; TimedOut: TTimedOutEvent): IObject;
  204. var
  205.   Thread: TCorbaBindThread;
  206.   CompleteEvent: THandle;
  207.   WaitResult: DWORD;
  208.   Cancel: Boolean;
  209.   TickCount: DWORD;
  210.   WaitTicks: DWORD;
  211.   CurTicks: DWORD;
  212.   ConnectMessage: string;
  213.   Exception: TObject;
  214.  
  215.   procedure ShowConnectDialog(const Msg: string);
  216.   var
  217.     MsgDialog: TForm;
  218.   begin
  219.     MsgDialog := CreateMessageDialog(Msg, mtInformation, [mbCancel]);
  220.     try
  221.       Thread.DialogHandle := MsgDialog.Handle;
  222.       MsgDialog.ShowModal;
  223.     finally
  224.       MsgDialog.Free;
  225.     end;
  226.   end;
  227.  
  228. begin
  229.   Thread := TCorbaBindThread.Create(RepId, FactoryId, InstanceName,
  230.     HostName, IID, Result);
  231.   try
  232.     CompleteEvent := Thread.CallCompleteEvent;
  233.     TickCount := GetTickCount;
  234.     WaitTicks := Timeout;
  235.     while not Thread.Finished do
  236.     begin
  237.       WaitResult := MsgWaitForMultipleObjects(1, CompleteEvent, False, WaitTicks,
  238.         QS_ALLINPUT);
  239.       case WaitResult of
  240.         WAIT_TIMEOUT:
  241.           begin
  242.             Cancel := False;
  243.             ConnectMessage := sConnecting;
  244.             if Assigned(TimedOut) then TimedOut(ConnectMessage, Cancel);
  245.             if not Thread.Finished and not Cancel and (ConnectMessage <> '') then
  246.             begin
  247.               ShowConnectDialog(ConnectMessage);
  248.               Cancel := True;
  249.             end;
  250.             if Cancel and not Thread.Finished then
  251.             begin
  252.               Thread.Cancel;
  253.               Result := nil;
  254.               Abort;
  255.             end;
  256.             TickCount := GetTickCount;
  257.             WaitTicks := Timeout;
  258.           end;
  259.         $FFFFFFFF: RaiseLastWin32Error;
  260.       else
  261.         if Thread.Finished then Break;
  262.         Application.ProcessMessages;
  263.         CurTicks := GetTickCount;
  264.         if TickCount + TimeOut > CurTicks then
  265.           WaitTicks := TickCount + TimeOut - CurTicks else
  266.           WaitTicks := 0;
  267.       end;
  268.     end;
  269.     if Thread.Exception <> nil then
  270.     begin
  271.       Exception := Thread.Exception;
  272.       Thread.Exception := nil;
  273.       raise Exception;
  274.     end;
  275.   finally
  276.     Thread.MarkFreeable;
  277.   end;
  278. end;
  279.  
  280. { TCorbaConnection }
  281.  
  282. constructor TCorbaConnection.Create(AOwner: TComponent);
  283. begin
  284.   inherited Create(AOwner);
  285. end;
  286.  
  287. procedure TCorbaConnection.SetRepositoryId(const Value: TRepositoryId);
  288. begin
  289.   if Value <> FRepositoryId then
  290.   begin
  291.     if not (csLoading in ComponentState) then
  292.     begin
  293.       SetConnected(False);
  294.     end;
  295.     FRepositoryId := Value;
  296.   end;
  297. end;
  298.  
  299. procedure TCorbaConnection.SetObjectName(const Value: string);
  300. begin
  301.   if Value <> FObjectName then
  302.   begin
  303.     if not (csLoading in ComponentState) then
  304.     begin
  305.       SetConnected(False);
  306.     end;
  307.     FObjectName := Value;
  308.   end;
  309. end;
  310.  
  311. procedure TCorbaConnection.SetHostName(const Value: string);
  312. begin
  313.   if Value <> FHostName then
  314.   begin
  315.     if not (csLoading in ComponentState) then
  316.     begin
  317.       SetConnected(False);
  318.     end;
  319.     FHostName := Value;
  320.   end;
  321. end;
  322.  
  323. function TCorbaConnection.GetConnected: Boolean;
  324. begin
  325.   Result := (not VarIsNull(AppServer) and (IUnknown(AppServer) <> nil));
  326. end;
  327.  
  328. procedure TCorbaConnection.SetConnected(Value: Boolean);
  329. begin
  330.   Sleep(0);
  331.   if (not (csReading in ComponentState)) and
  332.      (Value and not Connected) and
  333.      (FRepositoryId = '') then
  334.     raise Exception.CreateResFmt(@SRepositoryIdBlank, [Name]);
  335.   inherited SetConnected(Value);
  336. end;
  337.  
  338. procedure TCorbaConnection.DoDisconnect;
  339. begin
  340.   SetAppServer(NULL);
  341. end;
  342.  
  343. function TCorbaConnection.GetAppServer: Variant;
  344. begin
  345.   Result := FAppServer;
  346. end;
  347.  
  348. procedure TCorbaConnection.SetAppServer(Value: Variant);
  349. begin
  350.   FAppServer := Value;
  351. end;
  352.  
  353. procedure TCorbaConnection.GetProviderNames(Proc: TGetStrProc);
  354. var
  355.   List: Variant;
  356.   I: Integer;
  357. begin
  358.   Connected := True;
  359.   VarClear(List);
  360.   try
  361.     List := (IUnknown(AppServer) as IAppServer).AS_GetProviderNames;
  362.   except
  363.     { Assume any errors means the list is not available. }
  364.   end;
  365.   if VarIsArray(List) and (VarArrayDimCount(List) = 1) then
  366.     for I := VarArrayLowBound(List, 1) to VarArrayHighBound(List, 1) do
  367.       Proc(List[I]);
  368. end;
  369.  
  370. procedure TCorbaConnection.DoConnect;
  371. const
  372.   SPrefix = 'IDL:';   // Do not localize
  373.   PrefixLength = Length(SPrefix);
  374.   SFactory = 'Factory';
  375. var
  376.   Intf: IUnknown;
  377.   FactoryId, ObjectId: string;
  378.   IID: TGuid;
  379.   P: Integer;
  380. begin
  381.   if FConnecting then Exit;
  382.   FConnecting := True;
  383.   try
  384.     CorbaInitialize;
  385.     if (Length(RepositoryId) <= PrefixLength) or
  386.     (AnsiCompareStr(Copy(RepositoryId, 1, PrefixLength), SPrefix) <> 0) then
  387.     begin
  388.       FactoryId := Format('%s%s%s:1.0', [SPrefix, RepositoryId, SFactory]);
  389.       ObjectId := Format('%s%s:1.0', [SPrefix, RepositoryId]);
  390.     end
  391.     else
  392.     begin
  393.       FactoryId := RepositoryId;
  394.       ObjectId := RepositoryId;
  395.       P := Pos(SFactory+':', ObjectId);
  396.       if P > 0 then
  397.         Delete(ObjectId, P, Length(SFactory));
  398.     end;
  399.     // Object ID has 'I' before object name
  400.     P := Pos('/', ObjectID);
  401.     if (P > 0) and (P < Length(ObjectId)) then
  402.       Insert('I', ObjectID, P + 1);
  403.     if not CorbaInterfaceIDManager.SearchGuid(ObjectId, IID) then
  404.       IID := IAppServer;
  405.     if FCancelable or (csDesigning in ComponentState) then
  406.       Intf := ThreadedBind(FactoryId, ObjectName, '', HostName, IID,
  407.         1000, ThreadTimeout)
  408.     else
  409.       Intf := CORBAFactoryCreateStub(FactoryId, ObjectName,
  410.         '', HostName, IID);
  411.     if Intf <> nil then
  412.       SetAppServer(Intf);
  413.   finally
  414.     FConnecting := False;
  415.   end;
  416. end;
  417.  
  418. procedure TCorbaConnection.ThreadTimeout(var DialogMessage: string;
  419.   var Cancel: Boolean);
  420. begin
  421.   if Assigned(FOnCancel) then FOnCancel(Self, Cancel, DialogMessage);
  422. end;
  423.  
  424. function TCorbaConnection.GetServer: IAppServer;
  425. begin
  426.   Connected := True;
  427.   Result := IUnknown(AppServer) as IAppServer;
  428. end;
  429.  
  430. end.
  431.