www.pudn.com > Roulette.rar > SConnect.pas


 
{*******************************************************} 
{                                                       } 
{       Borland Delphi Visual Component Library         } 
{       Streamed Connection classes                     } 
{                                                       } 
{       Copyright (c) 1997,99 Inprise Corporation       } 
{                                                       } 
{*******************************************************} 
 
unit SConnect; 
 
{$R-} 
 
interface 
 
uses 
  Variants, Windows, Messages, Classes, SysUtils, ScktComp, WinSock, 
  WinInet, ComObj; 
 
type 
 
  {$HPPEMIT '#pragma link "wininet.lib"'} 
 
  { IDataBlock } 
  TLoginEvent = procedure(Sender: TObject; Username, Password: string) of object; 
 
  IDataBlock = interface(IUnknown) 
  ['{CA6564C2-4683-11D1-88D4-00A0248E5091}'] 
    function GetBytesReserved: Integer; stdcall; 
    function GetMemory: Pointer; stdcall; 
    function GetSize: Integer; stdcall; 
    procedure SetSize(Value: Integer); stdcall; 
    function GetStream: TStream; stdcall; 
    function GetSignature: Integer; stdcall; 
    procedure SetSignature(Value: Integer); stdcall; 
    procedure Clear; stdcall; 
    function Write(const Buffer; Count: Integer): Integer; stdcall; 
    function Read(var Buffer; Count: Integer): Integer; stdcall; 
    procedure IgnoreStream; stdcall; 
    function InitData(Data: Pointer; DataLen: Integer; CheckLen: Boolean): Integer; stdcall; 
    property BytesReserved: Integer read GetBytesReserved; 
    property Memory: Pointer read GetMemory; 
    property Signature: Integer read GetSignature write SetSignature; 
    property Size: Integer read GetSize write SetSize; 
    property Stream: TStream read GetStream; 
  end; 
 
  { ISendDataBlock } 
 
  ISendDataBlock = interface 
  ['{87AD1043-470E-11D1-88D5-00A0248E5091}'] 
    function Send(const Data: IDataBlock; WaitForResult: Boolean): IDataBlock; stdcall; 
  end; 
 
  { ITransport } 
 
  ITransport = interface(IUnknown) 
  ['{CA6564C1-4683-11D1-88D4-00A0248E5091}'] 
    function GetWaitEvent: THandle; stdcall; 
    function GetConnected: Boolean; stdcall; 
    procedure SetConnected(Value: Boolean); stdcall; 
    function Receive(WaitForInput: Boolean; Context: Integer): IDataBlock; stdcall; 
    function Send(const Data: IDataBlock): Integer; stdcall; 
    property Connected: Boolean read GetConnected write SetConnected; 
  end; 
 
  { IDataIntercept } 
 
  IDataIntercept = interface 
  ['{B249776B-E429-11D1-AAA4-00C04FA35CFA}'] 
    procedure DataIn(const Data: IDataBlock); stdcall; 
    procedure DataOut(const Data: IDataBlock); stdcall; 
  end; 
 
  { TDataBlock } 
 
  TDataBlock = class(TInterfacedObject, IDataBlock) 
  private 
    FStream: TMemoryStream; 
    FReadPos: Integer; 
    FWritePos: Integer; 
    FIgnoreStream: Boolean; 
  protected 
    { IDataBlock } 
    function GetBytesReserved: Integer; stdcall; 
    function GetMemory: Pointer; stdcall; 
    function GetSize: Integer; stdcall; 
    procedure SetSize(Value: Integer); stdcall; 
    function GetStream: TStream; stdcall; 
    function GetSignature: Integer; stdcall; 
    procedure SetSignature(Value: Integer); stdcall; 
    procedure Clear; stdcall; 
    function Write(const Buffer; Count: Integer): Integer; stdcall; 
    function Read(var Buffer; Count: Integer): Integer; stdcall; 
    procedure IgnoreStream; stdcall; 
    function InitData(Data: Pointer; DataLen: Integer; CheckLen: Boolean): Integer; stdcall; 
    property BytesReserved: Integer read GetBytesReserved; 
    property Memory: Pointer read GetMemory; 
    property Signature: Integer read GetSignature write SetSignature; 
    property Size: Integer read GetSize write SetSize; 
    property Stream: TStream read GetStream; 
  public 
    constructor Create; 
    destructor Destroy; override; 
  end; 
 
  { TDataBlockInterpreter } 
 
const 
 
  { Action Signatures } 
 
  CallSig         = $DA00; // Call signature 
  ResultSig       = $DB00; // Result signature 
  asError         = $01;   // Specify an exception was raised 
  asInvoke        = $02;   // Specify a call to Invoke 
  asGetID         = $03;   // Specify a call to GetIdsOfNames 
  asCreateObject  = $04;   // Specify a com object to create 
  asFreeObject    = $05;   // Specify a dispatch to free 
  asGetServers    = $10;   // Get classname list 
  asGetGUID       = $11;   // Get GUID for ClassName 
  asGetAppServers = $12;   // Get AppServer classname list 
  asSoapCommand   = $14;   // Soap command 
  asMask          = $FF;   // Mask for action 
 
type 
 
  PIntArray = ^TIntArray; 
  TIntArray = array[0..0] of Integer; 
 
  PVariantArray = ^TVariantArray; 
  TVariantArray = array[0..0] of OleVariant; 
 
  TVarFlag = (vfByRef, vfVariant); 
  TVarFlags = set of TVarFlag; 
 
  EInterpreterError = class(Exception); 
 
  TDataDispatch = class; 
 
 
  TCustomDataBlockInterpreter = class 
  protected 
    procedure AddDispatch(Value: TDataDispatch); virtual; abstract; 
    procedure RemoveDispatch(Value: TDataDispatch); virtual; abstract; 
 
    { Sending Calls } 
    procedure CallFreeObject(DispatchIndex: Integer); virtual; abstract; 
    function CallGetIDsOfNames(DispatchIndex: Integer; const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; virtual; stdcall; abstract; 
    function CallInvoke(DispatchIndex, DispID: Integer; const IID: TGUID; LocaleID: Integer; 
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; virtual; stdcall; abstract; 
    function CallGetServerList: OleVariant; virtual; abstract; 
 
    { Receiving Calls } 
 
 
    function InternalCreateObject(const ClassID: TGUID): OleVariant; virtual; abstract; 
    function CreateObject(const Name: string): OleVariant; virtual; abstract; 
    function StoreObject(const Value: OleVariant): Integer; virtual; abstract; 
    function LockObject(ID: Integer): IDispatch; virtual; abstract; 
    procedure UnlockObject(ID: Integer; const Disp: IDispatch); virtual; abstract; 
    procedure ReleaseObject(ID: Integer); virtual; abstract; 
    function CanCreateObject(const ClassID: TGUID): Boolean; virtual; abstract; 
    function CallCreateObject(Name: string): OleVariant;  virtual;  abstract; 
  public 
    procedure InterpretData(const Data: IDataBlock); virtual; abstract; 
  end; 
 
 
  { TBinary... } 
  TDataBlockInterpreter = class(TCustomDataBlockInterpreter) 
  protected 
    FDispatchList: TList; 
    FDispList: OleVariant; 
    FSendDataBlock: ISendDataBlock; 
    FCheckRegValue: string; 
    function GetVariantPointer(const Value: OleVariant): Pointer; 
    procedure CopyDataByRef(const Source: TVarData; var Dest: TVarData); 
    function ReadArray(VType: Integer; const Data: IDataBlock): OleVariant; 
    procedure WriteArray(const Value: OleVariant; const Data: IDataBlock); 
    function ReadVariant(out Flags: TVarFlags; const Data: IDataBlock): OleVariant; 
    procedure WriteVariant(const Value: OleVariant; const Data: IDataBlock); 
    procedure DoException(const Data: IDataBlock); virtual; 
  protected 
    procedure AddDispatch(Value: TDataDispatch); override; 
    procedure RemoveDispatch(Value: TDataDispatch); override; 
    function InternalCreateObject(const ClassID: TGUID): OleVariant; override; 
    function CreateObject(const Name: string): OleVariant; override; 
    function StoreObject(const Value: OleVariant): Integer; override; 
    function LockObject(ID: Integer): IDispatch; override; 
    procedure UnlockObject(ID: Integer; const Disp: IDispatch); override; 
    procedure ReleaseObject(ID: Integer); override; 
    function CanCreateObject(const ClassID: TGUID): Boolean; override; 
 
    {Sending Calls} 
    procedure CallFreeObject(DispatchIndex: Integer); override; 
    function CallGetIDsOfNames(DispatchIndex: Integer; const IID: TGUID; Names: Pointer; 
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; override; 
    function CallInvoke(DispatchIndex, DispID: Integer; const IID: TGUID; LocaleID: Integer; 
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult;  override; 
    function CallGetServerList: OleVariant; override; 
 
    {Receiving Calls} 
    procedure DoCreateObject(const Data: IDataBlock); 
    procedure DoFreeObject(const Data: IDataBlock); 
    procedure DoGetIDsOfNames(const Data: IDataBlock); 
    procedure DoInvoke(const Data: IDataBlock); 
 
    function DoCustomAction(Action: Integer; const Data: IDataBlock): Boolean; virtual; 
     
    procedure DoGetAppServerList(const Data: IDataBlock); 
    procedure DoGetServerList(const Data: IDataBlock); 
 
  public 
    constructor Create(SendDataBlock: ISendDataBlock; CheckRegValue: string); 
    destructor Destroy; override; 
    function CallCreateObject(Name: string): OleVariant;  override; 
    procedure InterpretData(const Data: IDataBlock); override; 
  end; 
 
{ TDataDispatch } 
 
  TDataDispatch = class(TInterfacedObject, IDispatch) 
  private 
    FDispatchIndex: Integer; 
    FInterpreter: TCustomDataBlockInterpreter; 
  protected 
    property DispatchIndex: Integer read FDispatchIndex; 
    { IDispatch } 
    function GetTypeInfoCount(out Count: Integer): HResult; stdcall; 
    function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; 
    function GetIDsOfNames(const IID: TGUID; Names: Pointer; 
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; 
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; 
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; 
  public 
    constructor Create(Interpreter: TCustomDataBlockInterpreter; DispatchIndex: Integer); 
    destructor Destroy; override; 
  end; 
 
  { TTransportThread } 
 
const 
  THREAD_SENDSTREAM       = WM_USER + 1; 
  THREAD_RECEIVEDSTREAM   = THREAD_SENDSTREAM + 1; 
  THREAD_EXCEPTION        = THREAD_RECEIVEDSTREAM + 1; 
  THREAD_SENDNOTIFY       = THREAD_EXCEPTION + 1; 
  THREAD_REPLACETRANSPORT = THREAD_SENDNOTIFY + 1; 
 
type 
 
  TTransportThread = class(TThread) 
  private 
    FParentHandle: THandle; 
    FSemaphore: THandle; 
    FTransport: ITransport; 
  public 
    constructor Create(AHandle: THandle; Transport: ITransport); virtual; 
    destructor Destroy; override; 
    property Semaphore: THandle read FSemaphore; 
    procedure Execute; override; 
  end; 
 
  { TStreamedConnection } 
 
  TStreamedConnection = class({TDispatchConnection}TComponent, ISendDataBlock) 
  private 
    FRefCount: Integer; 
    FHandle: THandle; 
    FTransport: TTransportThread; 
    FTransIntf: ITransport; 
    FInterpreter: TCustomDataBlockInterpreter; 
    FSupportCallbacks: Boolean; 
    FInterceptGUID: TGUID; 
    FInterceptName: string; 
 
    FStreamedConnected: Boolean; 
 
    FAfterConnect: TNotifyEvent; 
    FAfterDisconnect: TNotifyEvent; 
    FBeforeConnect: TNotifyEvent; 
    FBeforeDisconnect: TNotifyEvent; 
    FOnLogin: TLoginEvent; 
    FLoginPrompt: Boolean; 
 
 
    function GetHandle: THandle; 
    procedure TransportTerminated(Sender: TObject); 
    procedure SetSupportCallbacks(Value: Boolean); 
    procedure SetInterceptName(const Value: string); 
    function GetInterceptGUID: string; 
    procedure SetInterceptGUID(const Value: string); 
    procedure SetConnected(Value: Boolean); 
  protected 
    {cw.} 
    FConnected : boolean; 
    function GetConnected: Boolean; 
 
    { IUnknown } 
    function QueryInterface(const IID: TGUID; out Obj): HResult; reintroduce; stdcall; 
    function _AddRef: Integer; stdcall; 
    function _Release: Integer; stdcall; 
    { ISendDataBlock } 
    function Send(const Data: IDataBlock; WaitForResult: Boolean): IDataBlock; stdcall; 
 
    procedure InternalOpen; virtual; 
    procedure InternalClose; virtual; 
 
    procedure ThreadReceivedStream(var Message: TMessage); message THREAD_RECEIVEDSTREAM; 
    procedure ThreadException(var Message: TMessage); message THREAD_EXCEPTION; 
    procedure WndProc(var Message: TMessage); 
    function CreateTransport: ITransport; virtual; 
    procedure DoConnect;virtual; 
    procedure DoDisconnect; 
    procedure DoError(E: Exception); virtual; 
 
    function GetInterpreter: TCustomDataBlockInterpreter; virtual; 
 
    property Interpreter: TCustomDataBlockInterpreter read GetInterpreter; 
    property Handle: THandle read GetHandle; 
    property SupportCallbacks: Boolean read FSupportCallbacks write SetSupportCallbacks default True; 
    property InterceptGUID: string read GetInterceptGUID write SetInterceptGUID; 
    property InterceptName: string read FInterceptName write SetInterceptName; 
  public 
    function GetInterceptorList: OleVariant; virtual; 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    property Connected: Boolean read GetConnected write SetConnected default False; 
    property LoginPrompt: Boolean read FLoginPrompt write FLoginPrompt default False; 
    property AfterConnect: TNotifyEvent read FAfterConnect write FAfterConnect; 
    property BeforeConnect: TNotifyEvent read FBeforeConnect write FBeforeConnect; 
    property AfterDisconnect: TNotifyEvent read FAfterDisconnect write FAfterDisconnect; 
    property BeforeDisconnect: TNotifyEvent read FBeforeDisconnect write FBeforeDisconnect; 
    property OnLogin: TLoginEvent read FOnLogin write FOnLogin; 
 
  end; 
 
  { TSocketTransport } 
 
  ESocketConnectionError = class(Exception); 
 
  TSocketTransport = class(TInterfacedObject, ITransport) 
  private 
    FEvent: THandle; 
    FAddress: string; 
    FHost: string; 
    FPort: Integer; 
    FClientSocket: TClientSocket; 
    FSocket: TCustomWinSocket; 
    FInterceptGUID: string; 
    FInterceptor: IDataIntercept; 
    FCreateAttempted: Boolean; 
    function CheckInterceptor: Boolean; 
    procedure InterceptIncoming(const Data: IDataBlock); 
    procedure InterceptOutgoing(const Data: IDataBlock); 
  protected 
    { ITransport } 
    function GetWaitEvent: THandle; stdcall; 
    function GetConnected: Boolean; stdcall; 
    procedure SetConnected(Value: Boolean); stdcall; 
    function Receive(WaitForInput: Boolean; Context: Integer): IDataBlock; stdcall; 
    function Send(const Data: IDataBlock): Integer; stdcall; 
  public 
    constructor Create; 
    destructor Destroy; override; 
    property Host: string read FHost write FHost; 
    property Address: string read FAddress write FAddress; 
    property Port: Integer read FPort write FPort; 
    property Socket: TCustomWinSocket read FSocket write FSocket; 
    property InterceptGUID: string read FInterceptGUID write FInterceptGUID; 
  end; 
 
  { TSocketConnection } 
 
  TSocketConnection = class(TStreamedConnection) 
  private 
    FAddress: string; 
    FHost: string; 
    FPort: Integer; 
    procedure SetAddress(Value: string); 
    procedure SetHost(Value: string); 
    function IsHostStored: Boolean; 
    function IsAddressStored: Boolean; 
  protected 
    function CreateTransport: ITransport; override; 
    procedure DoConnect; override; 
  public 
    constructor Create(AOwner: TComponent); override; 
  published 
    property Address: string read FAddress write SetAddress stored IsAddressStored; 
    property Host: string read FHost write SetHost stored IsHostStored; 
    property InterceptGUID; 
    property InterceptName; 
    property Port: Integer read FPort write FPort default 211; 
    property SupportCallbacks; 
//    property ObjectBroker; 
  end; 
 
 
  { TPacketInterceptFactory } 
 
  TPacketInterceptFactory = class(TComObjectFactory) 
  public 
    procedure UpdateRegistry(Register: Boolean); override; 
  end; 
  {$EXTERNALSYM TPacketInterceptFactory} 
 
{ Utility functions } 
 
function LoadWinSock2: Boolean; 
procedure GetPacketInterceptorList(List: TStringList); 
 
var 
  WSACreateEvent: function: THandle stdcall; 
  WSAResetEvent: function(hEvent: THandle): Boolean stdcall; 
  WSACloseEvent: function(hEvent: THandle): Boolean stdcall; 
  WSAEventSelect: function(s: TSocket; hEventObject: THandle; lNetworkEvents: Integer): Integer stdcall; 
 
implementation 
 
uses 
  ActiveX, MidConst, RTLConsts; 
 
var 
  hWinSock2: THandle; 
 
{ Utility functions } 
 
function LoadWinSock2: Boolean; 
const 
  DLLName = 'ws2_32.dll'; 
begin 
  Result := hWinSock2 > 0; 
  if Result then Exit; 
  hWinSock2 := LoadLibrary(PChar(DLLName)); 
  Result := hWinSock2 > 0; 
  if Result then 
  begin 
    WSACreateEvent := GetProcAddress(hWinSock2, 'WSACreateEvent'); 
    WSAResetEvent := GetProcAddress(hWinSock2, 'WSAResetEvent'); 
    WSACloseEvent := GetProcAddress(hWinSock2, 'WSACloseEvent'); 
    WSAEventSelect := GetProcAddress(hWinSock2, 'WSAEventSelect'); 
  end; 
end; 
 
procedure GetPacketInterceptorList(List: TStringList); 
var 
  EnumGUID: IEnumGUID; 
  Fetched: Cardinal; 
  Guid: TGUID; 
  Rslt: HResult; 
  CatInfo: ICatInformation; 
  I: Integer; 
  ClassIDKey: HKey; 
  S: string; 
  Buffer: array[0..255] of Char; 
begin 
  List.Clear; 
  Rslt := CoCreateInstance(CLSID_StdComponentCategoryMgr, nil, 
    CLSCTX_INPROC_SERVER, ICatInformation, CatInfo); 
  if Succeeded(Rslt) then 
  begin 
    OleCheck(CatInfo.EnumClassesOfCategories(1, @CATID_MIDASInterceptor, 0, nil, EnumGUID)); 
    while EnumGUID.Next(1, Guid, Fetched) = S_OK do 
      List.Add(ClassIDToProgID(Guid)); 
  end else 
  begin 
    if RegOpenKey(HKEY_CLASSES_ROOT, 'CLSID', ClassIDKey) <> 0 then 
      try 
        I := 0; 
        while RegEnumKey(ClassIDKey, I, Buffer, SizeOf(Buffer)) = 0 do 
        begin 
          S := Format(SCatImplKey,[Buffer, GUIDToString(CATID_MIDASInterceptor)]); 
          List.Add(ClassIDToProgID(StringToGUID(Buffer))); 
          Inc(I); 
        end; 
      finally 
        RegCloseKey(ClassIDKey); 
      end; 
  end; 
end; 
 
procedure FreeWinSock2; 
begin 
  if hWinSock2 > 0 then 
  begin 
    WSACreateEvent := nil; 
    WSAResetEvent := nil; 
    WSACloseEvent := nil; 
    WSAEventSelect := nil; 
    FreeLibrary(hWinSock2); 
  end; 
  hWinSock2 := 0; 
end; 
 
procedure GetDataBrokerList(List: TStringList; const RegCheck: string); 
 
  function OpenRegKey(Key: HKey; const SubKey: string): HKey; 
  begin 
    if Windows.RegOpenKey(Key, PChar(SubKey), Result) <> 0 then Result := 0; 
  end; 
 
  function EnumRegKey(Key: HKey; Index: Integer; var Value: string): Boolean; 
  var 
    Buffer: array[0..255] of Char; 
  begin 
    Result := False; 
    if Windows.RegEnumKey(Key, Index, Buffer, SizeOf(Buffer)) = 0 then 
    begin 
      Value := Buffer; 
      Result := True; 
    end; 
  end; 
 
  function QueryRegKey(Key: HKey; const SubKey: string; 
    var Value: string): Boolean; 
  var 
    BufSize: Longint; 
    Buffer: array[0..255] of Char; 
  begin 
    Result := False; 
    BufSize := SizeOf(Buffer); 
    if Windows.RegQueryValue(Key, PChar(SubKey), Buffer, BufSize) = 0 then 
    begin 
      Value := Buffer; 
      Result := True; 
    end; 
  end; 
 
  procedure CloseRegKey(Key: HKey); 
  begin 
    RegCloseKey(Key); 
  end; 
 
var 
  I: Integer; 
  ClassIDKey: HKey; 
  ClassID, S: string; 
begin 
  List.Clear; 
  ClassIDKey := OpenRegKey(HKEY_CLASSES_ROOT, 'CLSID'); 
  if ClassIDKey <> 0 then 
    try 
      I := 0; 
      while EnumRegKey(ClassIDKey, I, ClassID) do 
      begin 
        if RegCheck <> '' then 
        begin 
          QueryRegKey(ClassIDKey, ClassID + '\' + RegCheck, S); 
          if S <> SFlagOn then continue; 
        end; 
        if not QueryRegKey(ClassIDKey, ClassID + '\Control', S) and 
           QueryRegKey(ClassIDKey, ClassID + '\ProgID', S) and 
           QueryRegKey(ClassIDKey, ClassID + '\TypeLib', S) and 
           QueryRegKey(ClassIDKey, ClassID + '\Version', S) and 
           QueryRegKey(ClassIDKey, ClassID + '\Borland DataBroker', S) then 
          List.Add(ClassIDToProgID(StringToGUID(ClassID))); 
        Inc(I); 
      end; 
    finally 
      CloseRegKey(ClassIDKey); 
    end; 
end; 
 
{ TDataBlock } 
 
constructor TDataBlock.Create; 
begin 
  inherited Create; 
  FIgnoreStream := False; 
  FStream := TMemoryStream.Create; 
  Clear; 
end; 
 
destructor TDataBlock.Destroy; 
begin 
  if not FIgnoreStream then 
    FStream.Free; 
  inherited Destroy; 
end; 
 
{ TDataBlock.IDataBlock } 
 
function TDataBlock.GetBytesReserved: Integer; 
begin 
  Result := SizeOf(Integer) * 2; 
end; 
 
function TDataBlock.GetMemory: Pointer; 
var 
  DataSize: Integer; 
begin 
  FStream.Position := 4; 
  DataSize := FStream.Size - BytesReserved; 
  FStream.Write(DataSize, SizeOf(DataSize)); 
  Result := FStream.Memory; 
end; 
 
function TDataBlock.GetSize: Integer; 
begin 
  Result := FStream.Size - BytesReserved; 
end; 
 
procedure TDataBlock.SetSize(Value: Integer); 
begin 
  FStream.Size := Value + BytesReserved; 
end; 
 
function TDataBlock.GetStream: TStream; 
var 
  DataSize: Integer; 
begin 
  FStream.Position := 4; 
  DataSize := FStream.Size - BytesReserved; 
  FStream.Write(DataSize, SizeOf(DataSize)); 
  FStream.Position := 0; 
  Result := FStream; 
end; 
 
function TDataBlock.GetSignature: Integer; 
begin 
  FStream.Position := 0; 
  FStream.Read(Result, SizeOf(Result)); 
end; 
 
procedure TDataBlock.SetSignature(Value: Integer); 
begin 
  FStream.Position := 0; 
  FStream.Write(Value, SizeOf(Value)); 
end; 
 
procedure TDataBlock.Clear; 
begin 
  FStream.Size := BytesReserved; 
  FReadPos := BytesReserved; 
  FWritePos := BytesReserved; 
end; 
 
function TDataBlock.Write(const Buffer; Count: Integer): Integer; 
begin 
  FStream.Position := FWritePos; 
  Result := FStream.Write(Buffer, Count); 
  FWritePos := FStream.Position; 
end; 
 
function TDataBlock.Read(var Buffer; Count: Integer): Integer; 
begin 
  FStream.Position := FReadPos; 
  Result := FStream.Read(Buffer, Count); 
  FReadPos := FStream.Position; 
end; 
 
procedure TDataBlock.IgnoreStream; 
begin 
  FIgnoreStream := True; 
end; 
 
function TDataBlock.InitData(Data: Pointer; DataLen: Integer; CheckLen: Boolean): Integer; stdcall; 
var 
  Sig: Integer; 
  P: Pointer; 
begin 
  P := Data; 
  if DataLen < 8 then   //4位标识4位长度 
    raise Exception.CreateRes(@SInvalidDataPacket); 
  Sig := Integer(P^); //标识 
  P := Pointer(Integer(Data) + SizeOf(Sig)); 
  if (Sig and CallSig <> CallSig) and //标识的8~15位固定 
     (Sig and ResultSig <> ResultSig) then 
    raise Exception.CreateRes(@SInvalidDataPacket); 
  Signature := Sig;  //调用标识 
  Result := Integer(P^); //返回值(数据长度) 
  P := Pointer(Integer(P) + SizeOf(Result)); 
  if CheckLen then //检测长度 
  begin 
    if (Result <> DataLen - 8) then 
      raise Exception.CreateRes(@SInvalidDataPacket); 
    Size := Result; 
    if Result > 0 then  //如果存在数据,则发送。 
      Write(P^, Result); 
  end else 
  begin 
    Size := DataLen - 8; 
    if Size > 0 then 
      Write(P^, Size); 
  end; 
end; 
 
{ TDataBlockInterpreter } 
 
const 
 
  EasyArrayTypes = [varSmallInt, varInteger, varSingle, varDouble, varCurrency, 
                    varDate, varBoolean, varByte]; 
 
  VariantSize: array[0..varByte] of Word  = (0, 0, SizeOf(SmallInt), SizeOf(Integer), 
    SizeOf(Single), SizeOf(Double), SizeOf(Currency), SizeOf(TDateTime), 0, 0, 
    SizeOf(Integer), SizeOf(WordBool), 0, 0, 0, 0, 0, SizeOf(Byte)); 
 
constructor TDataBlockInterpreter.Create(SendDataBlock: ISendDataBlock; CheckRegValue: string); 
begin 
  inherited Create; 
  FSendDataBlock := SendDataBlock; 
  FDispatchList := TList.Create; 
  FCheckRegValue := CheckRegValue; 
end; 
 
destructor TDataBlockInterpreter.Destroy; 
var 
  i: Integer; 
begin 
  for i := FDispatchList.Count - 1 downto 0 do 
    TDataDispatch(FDispatchList[i]).FInterpreter := nil; 
  FDispatchList.Free; 
  FSendDataBlock := nil; 
  inherited Destroy; 
end; 
 
procedure TDataBlockInterpreter.AddDispatch(Value: TDataDispatch); 
begin 
  if FDispatchList.IndexOf(Value) = -1 then 
    FDispatchList.Add(Value); 
end; 
 
procedure TDataBlockInterpreter.RemoveDispatch(Value: TDataDispatch); 
begin 
  FDispatchList.Remove(Value); 
end; 
 
{ Variant conversion methods } 
 
function TDataBlockInterpreter.GetVariantPointer(const Value: OleVariant): Pointer; 
begin 
  case VarType(Value) of 
    varEmpty, varNull: Result := nil; 
    varDispatch: Result := TVarData(Value).VDispatch; 
    varVariant: Result := @Value; 
    varUnknown: Result := TVarData(Value).VUnknown; 
  else 
    Result := @TVarData(Value).VPointer; 
  end; 
end; 
 
procedure TDataBlockInterpreter.CopyDataByRef(const Source: TVarData; var Dest: TVarData); 
var 
  VType: Integer; 
begin 
  VType := Source.VType; 
  if Source.VType and varArray = varArray then 
  begin 
    VarClear(OleVariant(Dest)); 
    SafeArrayCopy(PSafeArray(Source.VArray), PSafeArray(Dest.VArray)); 
  end else 
    case Source.VType and varTypeMask of 
      varEmpty, varNull: ; 
      varOleStr: 
      begin 
        if (Dest.VType and varTypeMask) <> varOleStr then 
          Dest.VOleStr := SysAllocString(Source.VOleStr) else 
        if (Dest.VType and varByRef) = varByRef then 
          SysReallocString(PBStr(Dest.VOleStr)^,Source.VOleStr) else 
          SysReallocString(Dest.VOleStr,Source.VOleStr); 
      end; 
      varDispatch: Dest.VDispatch := Source.VDispatch; 
      varVariant: CopyDataByRef(PVarData(Source.VPointer)^, Dest); 
      varUnknown: Dest.VUnknown := Source.VUnknown; 
    else 
      if Dest.VType = 0 then 
        OleVariant(Dest) := OleVariant(Source) else 
      if Dest.VType and varByRef = varByRef then 
      begin 
        VType := VType or varByRef; 
        Move(Source.VPointer, Dest.VPointer^, VariantSize[Source.VType and varTypeMask]); 
      end else 
        Move(Source.VPointer, Dest.VPointer, VariantSize[Source.VType and varTypeMask]); 
    end; 
  Dest.VType := VType; 
end; 
 
function TDataBlockInterpreter.ReadArray(VType: Integer; 
  const Data: IDataBlock): OleVariant; 
var 
  Flags: TVarFlags; 
  LoDim, HiDim, Indices, Bounds: PIntArray; 
  DimCount, VSize, i: Integer; 
  {P: Pointer;} 
  V: OleVariant; 
  LSafeArray: PSafeArray; 
  P: Pointer; 
begin 
  VarClear(Result); 
  Data.Read(DimCount, SizeOf(DimCount)); 
  VSize := DimCount * SizeOf(Integer); 
  GetMem(LoDim, VSize); 
  try 
    GetMem(HiDim, VSize); 
    try 
      Data.Read(LoDim^, VSize); 
      Data.Read(HiDim^, VSize); 
      GetMem(Bounds, VSize * 2); 
      try 
        for i := 0 to DimCount - 1 do 
        begin 
          Bounds[i * 2] := LoDim[i]; 
          Bounds[i * 2 + 1] := HiDim[i]; 
        end; 
        Result := VarArrayCreate(Slice(Bounds^,DimCount * 2), VType and varTypeMask); 
      finally 
        FreeMem(Bounds); 
      end; 
      if VType and varTypeMask in EasyArrayTypes then 
      begin 
        Data.Read(VSize, SizeOf(VSize)); 
        P := VarArrayLock(Result); 
        try 
          Data.Read(P^, VSize); 
        finally 
          VarArrayUnlock(Result); 
        end; 
      end else 
      begin 
        LSafeArray := PSafeArray(TVarData(Result).VArray); 
        GetMem(Indices, VSize); 
        try 
          FillChar(Indices^, VSize, 0); 
          for I := 0 to DimCount - 1 do 
            Indices[I] := LoDim[I]; 
          while True do 
          begin 
            V := ReadVariant(Flags, Data); 
            if VType and varTypeMask = varVariant then 
              OleCheck(SafeArrayPutElement(LSafeArray, Indices^, V)) else 
              OleCheck(SafeArrayPutElement(LSafeArray, Indices^, TVarData(V).VPointer^)); 
            Inc(Indices[DimCount - 1]); 
            if Indices[DimCount - 1] > HiDim[DimCount - 1] then 
              for i := DimCount - 1 downto 0 do 
                if Indices[i] > HiDim[i] then 
                begin 
                  if i = 0 then Exit; 
                  Inc(Indices[i - 1]); 
                  Indices[i] := LoDim[i]; 
                end; 
          end; 
        finally 
          FreeMem(Indices); 
        end; 
      end; 
    finally 
      FreeMem(HiDim); 
    end; 
  finally 
    FreeMem(LoDim); 
  end; 
end; 
 
procedure TDataBlockInterpreter.WriteArray(const Value: OleVariant; 
  const Data: IDataBlock); 
var 
  VType, VSize, i, DimCount, ElemSize: Integer; 
  LSafeArray: PSafeArray; 
  LoDim, HiDim, Indices: PIntArray; 
  V: OleVariant; 
  P: Pointer; 
begin 
  VType := VarType(Value); 
  LSafeArray := PSafeArray(TVarData(Value).VPointer); 
  Data.Write(VType, SizeOf(Integer)); 
  DimCount := VarArrayDimCount(Value); 
  Data.Write(DimCount, SizeOf(DimCount)); 
  VSize := SizeOf(Integer) * DimCount; 
  GetMem(LoDim, VSize); 
  try 
    GetMem(HiDim, VSize); 
    try 
      for i := 1 to DimCount do 
      begin 
        LoDim[i - 1] := VarArrayLowBound(Value, i); 
        HiDim[i - 1] := VarArrayHighBound(Value, i); 
      end; 
      Data.Write(LoDim^,VSize); 
      Data.Write(HiDim^,VSize); 
      if VType and varTypeMask in EasyArrayTypes then 
      begin 
        ElemSize := SafeArrayGetElemSize(LSafeArray); 
        VSize := 1; 
        for i := 0 to DimCount - 1 do 
          VSize := (HiDim[i] - LoDim[i] + 1) * VSize; 
        VSize := VSize * ElemSize; 
        P := VarArrayLock(Value); 
        try 
          Data.Write(VSize, SizeOf(VSize)); 
          Data.Write(P^,VSize); 
        finally 
          VarArrayUnlock(Value); 
        end; 
      end else 
      begin 
        GetMem(Indices, VSize); 
        try 
          for I := 0 to DimCount - 1 do 
            Indices[I] := LoDim[I]; 
          while True do 
          begin 
            if VType and varTypeMask <> varVariant then 
            begin 
              OleCheck(SafeArrayGetElement(LSafeArray, Indices^, TVarData(V).VPointer)); 
              TVarData(V).VType := VType and varTypeMask; 
            end else 
              OleCheck(SafeArrayGetElement(LSafeArray, Indices^, V)); 
            WriteVariant(V, Data); 
            Inc(Indices[DimCount - 1]); 
            if Indices[DimCount - 1] > HiDim[DimCount - 1] then 
              for i := DimCount - 1 downto 0 do 
                if Indices[i] > HiDim[i] then 
                begin 
                  if i = 0 then Exit; 
                  Inc(Indices[i - 1]); 
                  Indices[i] := LoDim[i]; 
                end; 
          end; 
        finally 
          FreeMem(Indices); 
        end; 
      end; 
    finally 
      FreeMem(HiDim); 
    end; 
  finally 
    FreeMem(LoDim); 
  end; 
end; 
 
function TDataBlockInterpreter.ReadVariant(out Flags: TVarFlags; 
  const Data: IDataBlock): OleVariant; 
var 
  I, VType: Integer; 
  W: WideString; 
  TmpFlags: TVarFlags; 
begin 
  VarClear(Result); 
  Flags := []; 
  Data.Read(VType, SizeOf(VType)); 
  if VType and varByRef = varByRef then Include(Flags, vfByRef); 
  if VType = varByRef then 
  begin 
    Include(Flags, vfVariant); 
    Result := ReadVariant(TmpFlags, Data); 
    Exit; 
  end; 
  if vfByRef in Flags then VType := VType xor varByRef; 
  if (VType and varArray) = varArray then 
    Result := ReadArray(VType, Data) else 
  case VType and varTypeMask of 
    varEmpty: VarClear(Result); 
    varNull: Result := NULL; 
    varOleStr: 
    begin 
      Data.Read(I, SizeOf(Integer)); 
      SetLength(W, I); 
      Data.Read(W[1], I * 2); 
      Result := W; 
    end; 
    varDispatch: 
    begin 
      Data.Read(I, SizeOf(Integer)); 
      Result := TDataDispatch.Create(Self, I) as IDispatch; 
    end; 
    varUnknown: 
      raise EInterpreterError.CreateResFmt(@SBadVariantType,[IntToHex(VType,4)]); 
  else 
    TVarData(Result).VType := VType; 
    Data.Read(TVarData(Result).VPointer, VariantSize[VType and varTypeMask]); 
  end; 
end; 
 
function TDataBlockInterpreter.CanCreateObject(const ClassID: TGUID): Boolean; 
begin 
  Result := (FCheckRegValue = '') or 
    (GetRegStringValue(SClsid + GuidToString(ClassID), FCheckRegValue) = SFlagOn); 
end; 
 
function TDataBlockInterpreter.InternalCreateObject(const ClassID: TGUID): OleVariant; 
var 
  Unk: IUnknown; 
begin 
  OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or 
    CLSCTX_LOCAL_SERVER or CLSCTX_REMOTE_SERVER, IUnknown, Unk)); 
  Result := Unk as IDispatch; 
end; 
 
function TDataBlockInterpreter.CreateObject(const Name: string): OleVariant; 
var 
  ClassID: TGUID; 
begin 
  if (Name[1] = '{') and (Name[Length(Name)] = '}') then 
    ClassID := StringToGUID(Name) else 
    ClassID := ProgIDToClassID(Name); 
  if CanCreateObject(ClassID) then 
    Result := InternalCreateObject(ClassID) else 
    raise Exception.CreateResFmt(@SObjectNotAvailable, [GuidToString(ClassID)]); 
end; 
 
function TDataBlockInterpreter.StoreObject(const Value: OleVariant): Integer; 
begin 
  if not VarIsArray(FDispList) then 
    FDispList := VarArrayCreate([0,10], varVariant); 
  Result := 0; 
  while Result <= VarArrayHighBound(FDispList, 1) do 
    if VarIsClear(FDispList[Result]) then break else Inc(Result); 
  if Result > VarArrayHighBound(FDispList, 1) then 
    VarArrayRedim(FDispList, Result + 10); 
  FDispList[Result] := Value; 
end; 
 
function TDataBlockInterpreter.LockObject(ID: Integer): IDispatch; 
begin 
  Result := FDispList[ID]; 
end; 
 
procedure TDataBlockInterpreter.UnlockObject(ID: Integer; const Disp: IDispatch); 
begin 
end; 
 
procedure TDataBlockInterpreter.ReleaseObject(ID: Integer); 
begin 
  if (ID >= 0) and (VarIsArray(FDispList)) and 
     (ID < VarArrayHighBound(FDispList, 1)) then 
    FDispList[ID] := UNASSIGNED; 
end; 
 
procedure TDataBlockInterpreter.WriteVariant(const Value: OleVariant; 
  const Data: IDataBlock); 
var 
  I, VType: Integer; 
  W: WideString; 
begin 
  VType := VarType(Value); 
  if VarIsArray(Value) then 
    WriteArray(Value, Data) else 
  case (VType and varTypeMask) of 
    varEmpty, varNull: Data.Write(VType, SizeOf(Integer)); 
    varOleStr: 
    begin 
      W := WideString(Value); 
      I := Length(W); 
      Data.Write(VType, SizeOf(Integer)); 
      Data.Write(I,SizeOf(Integer)); 
      Data.Write(W[1], I * 2); 
    end; 
    varDispatch: 
    begin 
      if VType and varByRef = varByRef then 
        raise EInterpreterError.CreateResFmt(@SBadVariantType,[IntToHex(VType,4)]); 
      I := StoreObject(Value); 
      Data.Write(VType, SizeOf(Integer)); 
      Data.Write(I, SizeOf(Integer)); 
    end; 
    varVariant: 
    begin 
      if VType and varByRef <> varByRef then 
        raise EInterpreterError.CreateResFmt(@SBadVariantType,[IntToHex(VType,4)]); 
      I := varByRef; 
      Data.Write(I, SizeOf(Integer)); 
      WriteVariant(Variant(TVarData(Value).VPointer^), Data); 
    end; 
    varUnknown: 
      raise EInterpreterError.CreateResFmt(@SBadVariantType,[IntToHex(VType,4)]); 
  else 
    Data.Write(VType, SizeOf(Integer)); 
    if VType and varByRef = varByRef then 
      Data.Write(TVarData(Value).VPointer^, VariantSize[VType and varTypeMask]) else 
      Data.Write(TVarData(Value).VPointer, VariantSize[VType and varTypeMask]); 
  end; 
end; 
 
{ Sending Calls } 
 
function TDataBlockInterpreter.CallGetServerList: OleVariant; 
var 
  Flags: TVarFlags; 
  Data: IDataBlock; 
begin 
  Data := TDataBlock.Create as IDataBlock; 
  Data.Signature := CallSig or asGetAppServers; 
  Data := FSendDataBlock.Send(Data, True); 
  Result := ReadVariant(Flags, Data); 
end; 
 
function TDataBlockInterpreter.CallCreateObject(Name: string): OleVariant; 
var 
  Flags: TVarFlags; 
  Data: IDataBlock; 
begin 
  Data := TDataBlock.Create as IDataBlock; 
  WriteVariant(Name, Data); 
  Data.Signature := CallSig or asCreateObject; 
  Data := FSendDataBlock.Send(Data, True); 
  Result := ReadVariant(Flags, Data); 
end; 
 
procedure TDataBlockInterpreter.CallFreeObject(DispatchIndex: Integer); 
var 
  Data: IDataBlock; 
begin 
  Data := TDataBlock.Create as IDataBlock; 
  WriteVariant(DispatchIndex, Data); 
  Data.Signature := CallSig or asFreeObject; 
  FSendDataBlock.Send(Data, False); 
end; 
 
function TDataBlockInterpreter.CallGetIDsOfNames(DispatchIndex: Integer; 
  const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; 
  DispIDs: Pointer): HResult; stdcall; 
var 
  Flags: TVarFlags; 
  Data: IDataBlock; 
begin 
  if NameCount <> 1 then 
    Result := E_NOTIMPL else 
  begin 
    Data := TDataBlock.Create as IDataBlock; 
    WriteVariant(DispatchIndex, Data); 
    WriteVariant(WideString(POleStrList(Names)^[0]), Data); 
    Data.Signature := CallSig or asGetID; 
    Data := FSendDataBlock.Send(Data, True); 
    Result := ReadVariant(Flags, Data); 
    if Result = S_OK then 
      PDispIdList(DispIDs)^[0] := ReadVariant(Flags, Data); 
  end; 
end; 
 
function TDataBlockInterpreter.CallInvoke(DispatchIndex, DispID: Integer; const IID: TGUID; LocaleID: Integer; 
  Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; 
var 
  VarFlags: TVarFlags; 
  PDest: PVarData; 
  i: Integer; 
  Data: IDataBlock; 
begin 
  Data := TDataBlock.Create as IDataBlock; 
  WriteVariant(DispatchIndex, Data); 
  WriteVariant(DispID, Data); 
  WriteVariant(Flags, Data); 
  WriteVariant(VarResult <> nil, Data); 
  WriteVariant(PDispParams(@Params).cArgs, Data); 
  WriteVariant(PDispParams(@Params).cNamedArgs, Data); 
  for i := 0 to PDispParams(@Params).cNamedArgs - 1 do 
    WriteVariant(PDispParams(@Params).rgdispidNamedArgs[i], Data); 
  for i := 0 to PDispParams(@Params).cArgs - 1 do 
    WriteVariant(OleVariant(PDispParams(@Params).rgvarg^[i]), Data); 
  Data.Signature := CallSig or asInvoke; 
  Data := FSendDataBlock.Send(Data, True); 
  Result := ReadVariant(VarFlags, Data); 
  if (Result = DISP_E_EXCEPTION) then 
  begin 
    PExcepInfo(ExcepInfo).scode := ReadVariant(VarFlags, Data); 
    PExcepInfo(ExcepInfo).bstrDescription := ReadVariant(VarFlags, Data); 
  end; 
  for i := 0 to PDispParams(@Params).cArgs - 1 do 
    with PDispParams(@Params)^ do 
      if rgvarg^[i].vt and varByRef = varByRef then 
      begin 
        if rgvarg^[i].vt = (varByRef or varVariant) then 
          PDest := @TVarData(TVarData(rgvarg^[i]).VPointer^) else 
          PDest := @TVarData(rgvarg^[i]); 
        CopyDataByRef(TVarData(ReadVariant(VarFlags, Data)), PDest^); 
      end; 
  if VarResult <> nil then 
    PVariant(VarResult)^ := ReadVariant(VarFlags, Data); 
end; 
 
{ Receiving Calls } 
 
procedure TDataBlockInterpreter.InterpretData(const Data: IDataBlock); 
var 
  Action: Integer; 
begin 
  Action := Data.Signature; 
  if (Action and asMask) = asError then 
    DoException(Data); 
  try 
    case (Action and asMask) of 
      asInvoke: DoInvoke(Data);//调用请求 
      asGetID: DoGetIDsOfNames(Data); 
      asCreateObject: DoCreateObject(Data); 
      asFreeObject: DoFreeObject(Data); 
      asGetServers: DoGetServerList(Data); 
      asGetAppServers: DoGetAppServerList(Data); 
    else 
      if not DoCustomAction(Action and asMask, Data) then 
        raise EInterpreterError.CreateResFmt(@SInvalidAction, [Action and asMask]); 
    end; 
  except 
    on E: Exception do 
    begin 
      Data.Clear; 
      WriteVariant(E.Message, Data); 
      Data.Signature := ResultSig or asError; 
      FSendDataBlock.Send(Data, False); 
    end; 
  end; 
end; 
 
procedure TDataBlockInterpreter.DoException(const Data: IDataBlock); 
var 
  VarFlags: TVarFlags; 
begin 
  raise Exception.Create(ReadVariant(VarFlags, Data)); 
end; 
 
procedure TDataBlockInterpreter.DoGetAppServerList(const Data: IDataBlock); 
var 
  VList: OleVariant; 
  List: TStringList; 
  i: Integer; 
begin 
  Data.Clear; 
  List := TStringList.Create; 
  try 
//    GetMIDASAppServerList(List, FCheckRegValue); 
    if List.Count > 0 then 
    begin 
      VList := VarArrayCreate([0, List.Count - 1], varOleStr); 
      for i := 0 to List.Count - 1 do 
        VList[i] := List[i]; 
    end else 
      VList := NULL; 
  finally 
    List.Free; 
  end; 
  WriteVariant(VList, Data); 
  Data.Signature := ResultSig or asGetAppServers; 
  FSendDataBlock.Send(Data, False); 
end; 
 
procedure TDataBlockInterpreter.DoGetServerList(const Data: IDataBlock); 
var 
  VList: OleVariant; 
  List: TStringList; 
  i: Integer; 
begin 
  Data.Clear; 
  List := TStringList.Create; 
  try 
    GetDataBrokerList(List, FCheckRegValue); 
    if List.Count > 0 then 
    begin 
      VList := VarArrayCreate([0, List.Count - 1], varOleStr); 
      for i := 0 to List.Count - 1 do 
        VList[i] := List[i]; 
    end else 
      VList := NULL; 
  finally 
    List.Free; 
  end; 
  WriteVariant(VList, Data); 
  Data.Signature := ResultSig or asGetServers; 
  FSendDataBlock.Send(Data, False); 
end; 
 
procedure TDataBlockInterpreter.DoCreateObject(const Data: IDataBlock); 
var 
  V: OleVariant; 
  VarFlags: TVarFlags; 
  I: Integer; 
begin 
  V := CreateObject(ReadVariant(VarFlags, Data)); 
  Data.Clear; 
  I := TVarData(V).VType; 
  if (I and varTypeMask) = varInteger then 
  begin 
    I := varDispatch; 
    Data.Write(I, SizeOf(Integer)); 
    I := V; 
    Data.Write(I, SizeOf(Integer)); 
  end else 
    WriteVariant(V, Data); 
  Data.Signature := ResultSig or asCreateObject; 
  FSendDataBlock.Send(Data, False); 
end; 
 
procedure TDataBlockInterpreter.DoFreeObject(const Data: IDataBlock); 
var 
  VarFlags: TVarFlags; 
begin 
  try 
    ReleaseObject(ReadVariant(VarFlags, Data)); 
  except 
    { Don't return any exceptions } 
  end; 
end; 
 
procedure TDataBlockInterpreter.DoGetIDsOfNames(const Data: IDataBlock); 
var 
  ObjID, RetVal, DispID: Integer; 
  Disp: IDispatch; 
  W: WideString; 
  VarFlags: TVarFlags; 
begin 
  ObjID := ReadVariant(VarFlags, Data); 
  Disp := LockObject(ObjID); 
  try 
    W := ReadVariant(VarFlags, Data); 
    Data.Clear; 
    RetVal := Disp.GetIDsOfNames(GUID_NULL, @W, 1, 0, @DispID); 
  finally 
    UnlockObject(ObjID, Disp); 
  end; 
  WriteVariant(RetVal, Data); 
  if RetVal = S_OK then 
    WriteVariant(DispID, Data); 
  Data.Signature := ResultSig or asGetID; 
  FSendDataBlock.Send(Data, False); 
end; 
 
procedure TDataBlockInterpreter.DoInvoke(const Data: IDataBlock); 
var 
  ExcepInfo: TExcepInfo; 
  DispParams: TDispParams; 
  ObjID, DispID, Flags, i: Integer; 
  RetVal: HRESULT; 
  ExpectResult: Boolean; 
  VarFlags: TVarFlags; 
  Disp: IDispatch; 
  VarList: PVariantArray; 
  V: OleVariant; 
begin  // 
  VarList := nil;  //参数列表 
  FillChar(ExcepInfo, SizeOf(ExcepInfo), 0);//异常信息 
  FillChar(DispParams, SizeOf(DispParams), 0);//参数 
  ObjID := ReadVariant(VarFlags, Data);  //读取对象ID 
  Disp := LockObject(ObjID); // 找到对象 
  try 
    DispID := ReadVariant(VarFlags, Data);//读取调度ID 
    Flags := ReadVariant(VarFlags, Data);//读取数据标识 
    ExpectResult := ReadVariant(VarFlags, Data);//读取异常标识 
    DispParams.cArgs := ReadVariant(VarFlags, Data);//读取调度参数 
    DispParams.cNamedArgs := ReadVariant(VarFlags, Data);//读取调度参数名称 
    try 
      DispParams.rgdispidNamedArgs := nil;// 
      if DispParams.cNamedArgs > 0 then //名字参数 
      begin 
        GetMem(DispParams.rgdispidNamedArgs, DispParams.cNamedArgs * SizeOf(Integer)); 
        for i := 0 to DispParams.cNamedArgs - 1 do 
          DispParams.rgdispidNamedArgs[i] := ReadVariant(VarFlags, Data); 
      end; 
      if DispParams.cArgs > 0 then  //参数个数 
      begin 
        GetMem(DispParams.rgvarg, DispParams.cArgs * SizeOf(TVariantArg));//分配参数空间 
        GetMem(VarList, DispParams.cArgs * SizeOf(OleVariant));//分配参数空间 
        Initialize(VarList^, DispParams.cArgs); //分配列表空间 
        for i := 0 to DispParams.cArgs - 1 do 
        begin 
          VarList[i] := ReadVariant(VarFlags, Data); //依次读取参数 
          if vfByRef in VarFlags then //类型参考 
          begin 
            if vfVariant in VarFlags then //如果是变体 
            begin 
              DispParams.rgvarg[i].vt := varVariant or varByRef; 
              TVarData(DispParams.rgvarg[i]).VPointer := @VarList[i]; 
            end else 
            begin 
              DispParams.rgvarg[i].vt := VarType(VarList[i]) or varByRef; //如果是具体类型 
              TVarData(DispParams.rgvarg[i]).VPointer := GetVariantPointer(VarList[i]);//存正确指针 
            end; 
          end else 
            DispParams.rgvarg[i] := TVariantArg(VarList[i]);//无类型 
        end; 
      end; 
      Data.Clear; //清空数据包 
      RetVal := Disp.Invoke(DispID, GUID_NULL, 0, Flags, DispParams, @V, @ExcepInfo, nil);//AuotObject调用 
      WriteVariant(RetVal, Data);//写入返回结果 
      if RetVal = DISP_E_EXCEPTION then //如果调用异常 
      begin 
        WriteVariant(ExcepInfo.scode, Data); //返回异常码 
        WriteVariant(ExcepInfo.bstrDescription, Data);//返回异常描述 
      end; 
      if DispParams.rgvarg <> nil then //如果休要返回参数 
      begin 
        for i := 0 to DispParams.cArgs - 1 do //填写返回参数 
          if DispParams.rgvarg[i].vt and varByRef = varByRef then 
            WriteVariant(OleVariant(DispParams.rgvarg[i]), Data); 
      end; 
      if ExpectResult then WriteVariant(V, Data); //如果有返回值,写返回值 
      Data.Signature := ResultSig or asInvoke;//标识为调用返回 
      FSendDataBlock.Send(Data, False);//发送数据包 
    finally 
      if DispParams.rgdispidNamedArgs <> nil then //参数名称 
        FreeMem(DispParams.rgdispidNamedArgs);    //释放参数名称 
      if VarList <> nil then                      //释放值表 
      begin 
        Finalize(VarList^, DispParams.cArgs); 
        FreeMem(VarList); 
      end; 
      if DispParams.rgvarg <> nil then 
        FreeMem(DispParams.rgvarg); 
    end; 
  finally 
    UnlockObject(ObjID, Disp); 
  end; 
end; 
 
function TDataBlockInterpreter.DoCustomAction(Action: Integer; 
  const Data: IDataBlock): Boolean; 
begin 
  Result := False; 
end; 
 
{ TDataDispatch } 
 
constructor TDataDispatch.Create(Interpreter: TCustomDataBlockInterpreter; DispatchIndex: Integer); 
begin 
  inherited Create; 
  FDispatchIndex := DispatchIndex; 
  FInterpreter := Interpreter; 
  Interpreter.AddDispatch(Self); 
end; 
 
destructor TDataDispatch.Destroy; 
begin 
  if Assigned(FInterpreter) then 
  begin 
    FInterpreter.CallFreeObject(FDispatchIndex); 
    FInterpreter.RemoveDispatch(Self); 
  end; 
  inherited Destroy; 
end; 
 
{ TDataDispatch.IDispatch } 
 
function TDataDispatch.GetTypeInfoCount(out Count: Integer): HResult; stdcall; 
begin 
  Count := 0; 
  Result := S_OK; 
end; 
 
function TDataDispatch.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; 
begin 
  Result := E_NOTIMPL; 
end; 
 
function TDataDispatch.GetIDsOfNames(const IID: TGUID; Names: Pointer; 
  NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; 
begin 
  Result := FInterpreter.CallGetIDsOfNames(FDispatchIndex, IID, Names, NameCount, 
    LocaleID, DispIDs); 
end; 
 
function TDataDispatch.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; 
  Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; 
begin 
  Result := FInterpreter.CallInvoke(FDispatchIndex, DispID, IID, LocaleID, Flags, 
    Params, VarResult, ExcepInfo, ArgErr); 
end; 
 
 
{ TTransportThread } 
 
constructor TTransportThread.Create(AHandle: THandle; Transport: ITransport); 
begin 
  FParentHandle := AHandle; 
  FTransport := Transport; 
  FreeOnTerminate := True; 
  FSemaphore := CreateSemaphore(nil, 0, 1, nil); 
  inherited Create(False); 
end; 
 
destructor TTransportThread.Destroy; 
begin 
  CloseHandle(FSemaphore); 
  inherited Destroy; 
end; 
 
procedure TTransportThread.Execute; 
 
  procedure SynchronizeException; 
  var 
    SendException: TObject; 
  begin 
    SendException := AcquireExceptionObject; 
    if Assigned(FTransport) and (SendException is ESocketConnectionError) then 
      FTransport.Connected := False; 
    PostMessage(FParentHandle, THREAD_EXCEPTION, 0, Integer(Pointer(SendException))); 
  end; 
 
var 
  msg: TMsg; 
  Data: IDataBlock; 
  Event: THandle; 
  Context: Integer; 
begin 
  CoInitialize(nil); 
  try 
    PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE); 
    ReleaseSemaphore(FSemaphore, 1, nil); 
    try 
      FTransport.Connected := True; 
      try 
        Event := FTransport.GetWaitEvent; 
        while not Terminated and FTransport.Connected do 
        try 
          case MsgWaitForMultipleObjects(1, Event, False, INFINITE, QS_ALLINPUT) of 
            WAIT_OBJECT_0: 
            begin 
              WSAResetEvent(Event); 
              Data := FTransport.Receive(False, 0); 
              if Assigned(Data) then 
              begin 
                Data._AddRef; 
                PostMessage(FParentHandle, THREAD_RECEIVEDSTREAM, 0, Integer(Pointer(Data))); 
                Data := nil; 
              end; 
            end; 
            WAIT_OBJECT_0 + 1: 
            begin 
              while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do 
              begin 
                if (msg.hwnd = 0) then 
                  case msg.message of 
                    THREAD_SENDSTREAM: 
                    begin 
                      Data := IDataBlock(msg.lParam); 
                      Data._Release; 
                      Context := FTransport.Send(Data); 
                      if msg.wParam = 1 then 
                      begin 
                        Data := FTransport.Receive(True, Context); 
                        Data._AddRef; 
                        PostMessage(FParentHandle, THREAD_RECEIVEDSTREAM, 0, Integer(Pointer(Data))); 
                        Data := nil; 
                      end else 
                        PostMessage(FParentHandle, THREAD_SENDNOTIFY, 0, 0); 
                    end; 
                    THREAD_REPLACETRANSPORT: 
                    begin 
                      FTransport := ITransport(msg.lParam); 
                      FTransport._Release; 
                    end; 
                  else 
                    DispatchMessage(msg); 
                  end 
                else 
                  DispatchMessage(msg); 
              end; 
            end; 
          end; 
        except 
          SynchronizeException; 
        end; 
      finally 
        Data := nil; 
        FTransport.Connected := False; 
      end; 
    except 
      SynchronizeException; 
    end; 
  finally 
    FTransport := nil; 
    CoUninitialize(); 
  end; 
end; 
 
{ TStreamedConnection } 
 
constructor TStreamedConnection.Create(AOwner: TComponent); 
var 
  Obj: ISendDataBlock; 
begin 
  inherited Create(AOwner); 
  GetInterface(ISendDataBlock, Obj); 
//  FInterpreter := TDataBlockInterpreter.Create(Self, SSockets); 
  FSupportCallbacks := True; 
end; 
procedure TStreamedConnection.SetConnected(Value: Boolean); 
begin 
  if (csReading in ComponentState) and Value then 
    FStreamedConnected := True else 
  begin 
    if Value = GetConnected then Exit; 
    if Value then 
    begin 
      if Assigned(BeforeConnect) then BeforeConnect(Self); 
      DoConnect; 
//      SendConnectEvent(True); 
      if Assigned(AfterConnect) then AfterConnect(Self); 
    end else 
    begin 
      if Assigned(BeforeDisconnect) then BeforeDisconnect(Self); 
//      SendConnectEvent(False); 
      DoDisconnect; 
      if Assigned(AfterDisconnect) then AfterDisconnect(Self); 
    end; 
  end; 
end; 
 
 
destructor TStreamedConnection.Destroy; 
begin 
  SetConnected(False); 
  FInterpreter.Free; 
  if FHandle <> 0 then DeallocateHWnd(FHandle); 
  if Assigned(FTransport) then FTransport.OnTerminate := nil; 
  FTransIntf := nil; 
  inherited Destroy; 
end; 
 
function TStreamedConnection.GetInterceptGUID: string; 
begin 
  if (FInterceptGUID.D1 <> 0) or (FInterceptGUID.D2 <> 0) or (FInterceptGUID.D3 <> 0) then 
    Result := GUIDToString(FInterceptGUID) else 
    Result := ''; 
end; 
 
procedure TStreamedConnection.SetInterceptGUID(const Value: string); 
var 
  InterceptName: PWideChar; 
begin 
  if not (csLoading in ComponentState) then 
    SetConnected(False); 
  if Value = '' then 
    FillChar(FInterceptGUID, SizeOf(FInterceptGUID), 0) 
  else 
  begin 
    FInterceptGUID := StringToGUID(Value); 
    if ProgIDFromCLSID(FInterceptGUID, InterceptName) = 0 then 
    begin 
      FInterceptName := InterceptName; 
      CoTaskMemFree(InterceptName); 
    end; 
  end; 
end; 
 
procedure TStreamedConnection.SetInterceptName(const Value: string); 
begin 
  if Value <> FInterceptName then 
  begin 
    if not (csLoading in ComponentState) then 
    begin 
      SetConnected(False); 
      if CLSIDFromProgID(PWideChar(WideString(Value)), FInterceptGUID) <> 0 then 
        FillChar(FInterceptGUID, SizeOf(FInterceptGUID), 0); 
    end; 
    FInterceptName := Value; 
  end; 
end; 
 
procedure TStreamedConnection.SetSupportCallbacks(Value: Boolean); 
begin 
  if Connected then Connected := False; 
  FSupportCallbacks := Value; 
end; 
 
procedure TStreamedConnection.InternalOpen; 
begin 
  if FSupportCallbacks then 
  begin 
    FTransport := TTransportThread.Create(Handle, CreateTransport); 
    FTransport.OnTerminate := TransportTerminated; 
    WaitForSingleObject(FTransport.Semaphore, INFINITE); 
  end else 
  begin 
    FTransIntf := CreateTransport; 
    FTransIntf.SetConnected(True); 
  end; 
end; 
 
procedure TStreamedConnection.InternalClose; 
begin 
  if Assigned(FTransport) then 
  begin 
    FTransport.OnTerminate := nil; 
    FTransport.Terminate; 
    PostThreadMessage(FTransport.ThreadID, WM_USER, 0, 0); 
    WaitForSingleObject(FTransport.Handle, 180000); 
    FTransport := nil; 
  end else 
  if Assigned(FTransIntf) then 
  begin 
    FTransIntf.Connected := False; 
    FTransIntf := nil; 
  end; 
end; 
 
function TStreamedConnection.GetInterceptorList: OleVariant; 
var 
  List: TStringList; 
  i: Integer; 
begin 
  Result := NULL; 
  List := TStringList.Create; 
  try 
    GetPacketInterceptorList(List); 
    if List.Count > 0 then 
    begin 
      Result := VarArrayCreate([0, List.Count - 1], varOleStr); 
      for i := 0 to List.Count - 1 do 
        Result[i] := List[i]; 
    end; 
  finally 
    List.Free; 
  end; 
end; 
 
function TStreamedConnection.GetHandle: THandle; 
begin 
  if FHandle = 0 then 
    FHandle := AllocateHwnd(WndProc); 
  Result := FHandle; 
end; 
 
procedure TStreamedConnection.WndProc(var Message: TMessage); 
begin 
  try 
    Dispatch(Message); 
  except 
    if Assigned(ApplicationHandleException) then 
      ApplicationHandleException(Self); 
  end; 
end; 
 
procedure TStreamedConnection.ThreadReceivedStream(var Message: TMessage); 
var 
  Data: IDataBlock; 
begin 
  Data := IDataBlock(Message.lParam); 
  Data._Release; 
  Interpreter.InterpretData(Data); 
end; 
 
procedure TStreamedConnection.ThreadException(var Message: TMessage); 
begin 
  DoError(Exception(Message.lParam)); 
end; 
 
procedure TStreamedConnection.DoError(E: Exception); 
begin 
  raise E; 
end; 
 
procedure TStreamedConnection.TransportTerminated(Sender: TObject); 
begin 
  FTransport := nil; 
  SetConnected(False); 
end; 
 
procedure TStreamedConnection.DoConnect; 
var 
  TempStr: string; 
begin 
  try 
    InternalOpen; 
//    FConnected := (Interpreter as ).CallGetIDsOfNames() 
  except 
    InternalClose; 
    raise; 
  end; 
end; 
 
procedure TStreamedConnection.DoDisconnect; 
begin 
//  inherited DoDisconnect; 
  InternalClose; 
end; 
 
function TStreamedConnection.CreateTransport: ITransport; 
begin 
  Result := nil; 
end; 
 
function TStreamedConnection.GetInterpreter: TCustomDataBlockInterpreter; 
begin 
  if not Assigned(FInterpreter) then 
    FInterpreter := TDataBlockInterpreter.Create(Self, SSockets); 
  Result := FInterpreter; 
end; 
 
{ TStreamedConnection.IUnknown } 
 
function TStreamedConnection.QueryInterface(const IID: TGUID; out Obj): HResult; 
begin 
  if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; 
end; 
 
function TStreamedConnection._AddRef: Integer; 
begin 
  Inc(FRefCount); 
  Result := FRefCount; 
end; 
 
function TStreamedConnection._Release: Integer; 
begin 
  Dec(FRefCount); 
  Result := FRefCount; 
end; 
 
{ TStreamedConnection.ISendDataBlock } 
 
function TStreamedConnection.Send(const Data: IDataBlock; WaitForResult: Boolean): IDataBlock; 
var 
  Msg: TMsg; 
  Context: Integer; 
begin 
  if FSupportCallbacks then 
  begin 
    if not Assigned(FTransport) then Exit; 
    Data._AddRef; 
    PostThreadMessage(FTransport.ThreadID, THREAD_SENDSTREAM, Ord(WaitForResult), 
      Integer(Pointer(Data))); 
    if WaitForResult then 
      while True do 
      begin 
        if GetMessage(Msg, FHandle, THREAD_RECEIVEDSTREAM, THREAD_EXCEPTION) then 
        begin 
          if Msg.message = THREAD_RECEIVEDSTREAM then 
          begin 
            Result := IDataBlock(Msg.lParam); 
            Result._Release; 
            if (Result.Signature and ResultSig) = ResultSig then 
              break else 
              Interpreter.InterpretData(Result); 
          end else 
            DoError(Exception(Msg.lParam)); 
        end else 
          raise Exception.CreateRes(@SReturnError); 
      end 
    else 
      GetMessage(Msg, FHandle, THREAD_SENDNOTIFY, THREAD_SENDNOTIFY); 
  end else 
  begin 
    if not Assigned(FTransIntf) then Exit; 
    Context := FTransIntf.Send(Data); 
    Result := FTransIntf.Receive(WaitForResult, Context); 
  end; 
  if Assigned(Result) and ((Result.Signature and asMask) = asError) then 
    Interpreter.InterpretData(Result); 
end; 
 
function TStreamedConnection.GetConnected: Boolean; 
begin 
  if SupportCallbacks then 
  begin 
    Result := (FTransport<>nil) and (FTransport.FTransport<>nil) and(FTransport.FTransport.Connected); 
  end 
  else 
    Result := (FTransIntf<>nil) and( FTransIntf.Connected); 
end; 
 
{ TSocketTransport } 
 
constructor TSocketTransport.Create; 
begin 
  inherited Create; 
  FInterceptor := nil; 
  FEvent := 0; 
end; 
 
destructor TSocketTransport.Destroy; 
begin 
  FInterceptor := nil; 
  SetConnected(False); 
  inherited Destroy; 
end; 
 
function TSocketTransport.GetWaitEvent: THandle; 
begin 
  FEvent := WSACreateEvent; 
  WSAEventSelect(FSocket.SocketHandle, FEvent, FD_READ or FD_CLOSE); 
  Result := FEvent; 
end; 
 
function TSocketTransport.GetConnected: Boolean; 
begin 
  Result := (FSocket <> nil) and (FSocket.Connected); 
end; 
 
procedure TSocketTransport.SetConnected(Value: Boolean); 
begin 
  if GetConnected = Value then Exit; 
  if Value then 
  begin 
    if (FAddress = '') and (FHost = '') then 
      raise ESocketConnectionError.CreateRes(@SNoAddress); 
    FClientSocket := TClientSocket.Create(nil); 
    FClientSocket.ClientType := ctBlocking; 
    FSocket := FClientSocket.Socket; 
    FClientSocket.Port := FPort; 
 
    if FAddress <> '' then 
      FClientSocket.Address := FAddress else 
      FClientSocket.Host := FHost; 
    FClientSocket.Open; 
  end else 
  begin 
    FSocket.Close; 
    FClientSocket.Free; 
    if FEvent <> 0 then WSACloseEvent(FEvent); 
  end; 
end; 
 
function TSocketTransport.Receive(WaitForInput: Boolean; Context: Integer): IDataBlock; 
var 
  RetLen, Sig, StreamLen: Integer; 
  P: Pointer; 
  FDSet: TFDSet; 
  TimeVal: PTimeVal; 
  RetVal: Integer; 
begin 
  Result := nil; 
  TimeVal := nil; 
  FD_ZERO(FDSet); 
  FD_SET(FSocket.SocketHandle, FDSet); 
  if not WaitForInput then 
  begin 
    New(TimeVal); 
    TimeVal.tv_sec := 0; 
    TimeVal.tv_usec := 1; 
  end; 
  RetVal := select(0, @FDSet, nil, nil, TimeVal); 
  if Assigned(TimeVal) then 
    FreeMem(TimeVal); 
  if RetVal = SOCKET_ERROR then 
    raise ESocketConnectionError.Create(SysErrorMessage(WSAGetLastError)); 
  if (RetVal = 0) then Exit; 
  RetLen := FSocket.ReceiveBuf(Sig, SizeOf(Sig)); 
  if RetLen <> SizeOf(Sig) then 
    raise ESocketConnectionError.CreateRes(@SSocketReadError); 
  if (Sig and CallSig <> CallSig) and 
     (Sig and ResultSig <> ResultSig) then 
    raise Exception.CreateRes(@SInvalidDataPacket); 
  RetLen := FSocket.ReceiveBuf(StreamLen, SizeOf(StreamLen)); 
  if RetLen = 0 then 
    raise ESocketConnectionError.CreateRes(@SSocketReadError); 
  if RetLen <> SizeOf(StreamLen) then 
    raise ESocketConnectionError.CreateRes(@SSocketReadError); 
  Result := TDataBlock.Create as IDataBlock; 
  Result.Size := StreamLen; 
  Result.Signature := Sig; 
  P := Result.Memory; 
  Inc(Integer(P), Result.BytesReserved); 
  while StreamLen > 0 do 
  begin 
    RetLen := FSocket.ReceiveBuf(P^, StreamLen); 
    if RetLen = 0 then 
      raise ESocketConnectionError.CreateRes(@SSocketReadError); 
    if RetLen > 0 then 
    begin 
      Dec(StreamLen, RetLen); 
      Inc(Integer(P), RetLen); 
    end; 
  end; 
  if StreamLen <> 0 then 
    raise ESocketConnectionError.CreateRes(@SInvalidDataPacket); 
  InterceptIncoming(Result); 
end; 
 
function TSocketTransport.Send(const Data: IDataBlock): Integer; 
var 
  P: Pointer; 
begin 
  Result := 0; 
  InterceptOutgoing(Data); 
  P := Data.Memory; 
  FSocket.SendBuf(P^, Data.Size + Data.BytesReserved); 
end; 
 
function TSocketTransport.CheckInterceptor: Boolean; 
var 
  GUID: TGUID; 
begin 
  if not Assigned(FInterceptor) and (FInterceptGUID <> '') then 
    if not FCreateAttempted then 
    try 
      FCreateAttempted := True; 
      Guid := StringToGuid(FInterceptGUID); 
      FInterceptor := CreateComObject(Guid) as IDataIntercept; 
    except 
      { raise no exception if the creating failed } 
    end; 
  Result := Assigned(FInterceptor); 
end; 
 
procedure TSocketTransport.InterceptIncoming(const Data: IDataBlock); 
begin 
  if CheckInterceptor then 
    FInterceptor.DataIn(Data); 
end; 
 
procedure TSocketTransport.InterceptOutgoing(const Data: IDataBlock); 
begin 
  if CheckInterceptor then 
    FInterceptor.DataOut(Data); 
end; 
 
{ TSocketConnection } 
 
constructor TSocketConnection.Create(AOwner: TComponent); 
begin 
  inherited Create(AOwner); 
  FPort := 211; 
end; 
 
function TSocketConnection.IsAddressStored: Boolean; 
begin 
  Result := (Address <> ''); 
end; 
 
procedure TSocketConnection.SetAddress(Value: string); 
begin 
  if Value <> '' then 
    FHost := ''; 
  FAddress := Value; 
end; 
 
function TSocketConnection.IsHostStored: Boolean; 
begin 
  Result :=(Host <> ''); 
end; 
 
procedure TSocketConnection.SetHost(Value: string); 
begin 
  if Value <> '' then 
    FAddress := ''; 
  FHost := Value; 
end; 
 
function TSocketConnection.CreateTransport: ITransport; 
var 
  SocketTransport: TSocketTransport; 
begin 
  if SupportCallbacks then 
    if not LoadWinSock2 then raise Exception.CreateRes(@SNoWinSock2); 
  if (FAddress = '') and (FHost = '') then 
    raise ESocketConnectionError.CreateRes(@SNoAddress); 
  SocketTransport := TSocketTransport.Create; 
  SocketTransport.Host := FHost; 
  SocketTransport.Address := FAddress; 
  SocketTransport.Port := FPort; 
  SocketTransport.InterceptGUID := InterceptGUID; 
  Result := SocketTransport as ITransport; 
end; 
 
procedure TSocketConnection.DoConnect; 
var 
  Comp: string; 
  p, i: Integer; 
begin 
//  if (ObjectBroker <> nil) then 
  begin 
    repeat 
      if FAddress <> '' then 
        Comp := FAddress else 
      if FHost <> '' then 
        Comp := FHost; 
      try 
        {p := ObjectBroker.GetPortForComputer(Comp); 
        if p > 0 then 
          FPort := p;} 
        p := 0; 
        for i := 1 to Length(Comp) do 
          if (Comp[i] in ['0'..'9', '.']) then 
            Inc(p, Ord(Comp[i] = '.')) else 
            break; 
        if p <> 3 then 
          Host := Comp else 
          Address := Comp; 
        inherited DoConnect; 
//        ObjectBroker.SetConnectStatus(Comp, True); 
      except 
//        ObjectBroker.SetConnectStatus(Comp, False); 
        FAddress := ''; 
        FHost := ''; 
      end; 
    until (Connected or SupportCallbacks); 
  end 
  // else 
   // inherited DoConnect; 
end; 
 
 
{ TPacketInterceptFactory } 
 
procedure TPacketInterceptFactory.UpdateRegistry(Register: Boolean); 
var 
  CatReg: ICatRegister; 
  Rslt: HResult; 
  CatInfo: TCATEGORYINFO; 
  Description: string; 
begin 
  inherited UpdateRegistry(Register); 
 
  Rslt := CoCreateInstance(CLSID_StdComponentCategoryMgr, nil, 
    CLSCTX_INPROC_SERVER, ICatRegister, CatReg); 
  if Succeeded(Rslt) then 
  begin 
    if Register then 
    begin 
      CatInfo.catid := CATID_MIDASInterceptor; 
      CatInfo.lcid := $0409; 
      StringToWideChar(MIDASInterceptor_CatDesc, CatInfo.szDescription, 
        Length(MIDASInterceptor_CatDesc) + 1); 
      OleCheck(CatReg.RegisterCategories(1, @CatInfo)); 
      OleCheck(CatReg.RegisterClassImplCategories(ClassID, 1, @CATID_MIDASInterceptor)); 
    end else 
    begin 
      OleCheck(CatReg.UnRegisterClassImplCategories(ClassID, 1, @CATID_MIDASInterceptor)); 
      DeleteRegKey(Format(SClsid + SCatImplBaseKey, [GUIDToString(ClassID)])); 
    end; 
  end else 
  begin 
    if Register then 
    begin 
      CreateRegKey('Component Categories\' + GUIDToString(CATID_MIDASInterceptor), '409', MIDASInterceptor_CatDesc); 
      CreateRegKey(Format(SClsid + SCatImplKey, [GUIDToString(ClassID), GUIDToString(CATID_MIDASInterceptor)]), '', ''); 
    end else 
    begin 
      DeleteRegKey(Format(SClsid + SCatImplKey, [GUIDToString(ClassID), GUIDToString(CATID_MIDASAppServer)])); 
      DeleteRegKey(Format(SClsid + SCatImplBaseKey, [GUIDToString(ClassID)])); 
    end; 
  end; 
  if Register then 
  begin 
    Description := GetRegStringValue(SClsid + GUIDToString(ClassID), ''); 
    CreateRegKey('AppID\' + GUIDToString(ClassID), '', Description); 
    CreateRegKey(SClsid + GUIDToString(ClassID), 'AppID', GUIDToString(ClassID)); 
  end else 
    DeleteRegKey('AppID\' + GUIDToString(ClassID)); 
end; 
 
 
initialization 
finalization 
  FreeWinSock2; 
end.