Subversion Repositories spacemission

Rev

Rev 16 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. unit DXPlay;
  2.  
  3. interface
  4.  
  5. {$INCLUDE DelphiXcfg.inc}
  6.  
  7. {$IFNDEF UseDirectPlay} // Daniel Marschall 12.04.2024 Added to avoid Windows showing "This app requires DirectPlay"
  8. {$MESSAGE ERROR 'If you want to use DXPlay.pas, please enable the IFDEF UseDirectPlay in DelphiXcfg.inc'}
  9. {$ENDIF}
  10.  
  11. uses
  12.   Windows, SysUtils, Classes, Forms, DXClass, ActiveX, DXETable,  
  13. {$IfDef StandardDX}
  14.   DirectDraw,
  15. // Delphi 2010 cannot be use DirectPlay8 because structure was not rewriten
  16. //  {$IfDef DX9}
  17. //  DirectPlay8, DX7toDX8;
  18. //  {$Else}
  19.   DirectPlay; //old wersion, current in directory
  20. //  {$EndIf}
  21. {$Else}
  22.   DirectX;
  23. {$EndIf}
  24.  
  25. type
  26.   {$IfDef DX9}
  27.   TDPID = DWORD;
  28.   {$EndIf}
  29.  
  30.   {  TDXPlayPlayer  }
  31.  
  32.   TDXPlayPlayer = class(TCollectionItem)
  33.   private
  34.     FData: Pointer;
  35.     FID: TDPID;
  36.     FName: string;
  37.     FRemotePlayer: Boolean;
  38.   public
  39.     property Data: Pointer read FData write FData;
  40.     property ID: TDPID read FID;
  41.     property Name: string read FName;
  42.     property RemotePlayer: Boolean read FRemotePlayer;
  43.   end;
  44.  
  45.   {  TDXPlayPlayers  }
  46.  
  47.   TDXPlayPlayers = class(TCollection)
  48.   private
  49.     function GetPlayer(Index: Integer): TDXPlayPlayer;
  50.   public
  51.     constructor Create;
  52.     function Find(ID: TDPID): TDXPlayPlayer;
  53.     function IndexOf(ID: TDPID): Integer;
  54.     property Players[Index: Integer]: TDXPlayPlayer read GetPlayer; default;
  55.   end;
  56.  
  57.   {  TDXPlayModemSetting  }
  58.  
  59.   TDXPlayModemSetting = class(TPersistent)
  60.   private
  61.     FEnabled: Boolean;
  62.     FPhoneNumber: string;
  63.     FModemName: string;
  64.     FModemNames: TStrings;
  65.     function GetModemNames: TStrings;
  66.   public
  67.     destructor Destroy; override;
  68.     procedure Assign(Source: TPersistent); override;
  69.     property ModemName: string read FModemName write FModemName;
  70.     property ModemNames: TStrings read GetModemNames;
  71.   published
  72.     property Enabled: Boolean read FEnabled write FEnabled;
  73.     property PhoneNumber: string read FPhoneNumber write FPhoneNumber;
  74.   end;
  75.  
  76.   {  TDXPlayTCPIPSetting  }
  77.  
  78.   TDXPlayTCPIPSetting = class(TPersistent)
  79.   private
  80.     FEnabled: Boolean;
  81.     FHostName: string;
  82.     FPort: Word;
  83.   public
  84.     procedure Assign(Source: TPersistent); override;
  85.   published
  86.     property Enabled: Boolean read FEnabled write FEnabled;
  87.     property HostName: string read FHostName write FHostName;
  88.     property Port: Word read FPort write FPort;
  89.   end;
  90.  
  91.   {  EDXPlayError  }
  92.  
  93.   EDXPlayError = class(Exception);
  94.  
  95.   {  TCustomDXPlay  }
  96.  
  97.   TDXPlayEvent = procedure(Sender: TObject; Player: TDXPlayPlayer) of object;
  98.  
  99.   TDXPlayMessageEvent = procedure(Sender: TObject; From: TDXPlayPlayer;
  100.     Data: Pointer; DataSize: Integer) of object;
  101.  
  102.   TDXPlaySendCompleteResult = (crOk, crAbort, crGeneric);
  103.  
  104.   TDXPlaySendCompleteEvent = procedure(Sender: TObject; MessageID: DWORD;
  105.     Result: TDXPlaySendCompleteResult; SendTime: Integer) of object;
  106.  
  107.   TCustomDXPlay = class(TComponent)
  108.   private
  109.     FDPlay: //{$IfDef DX7}
  110.       IDirectPlay4A;//{$Else}IDirectPlay8Address{$EndIf};
  111.     FGUID: string;
  112.     FIsHost: Boolean;
  113.     FLocalPlayer: TDXPlayPlayer;
  114.     FMaxPlayers: Integer;
  115.     FPlayers: TDXPlayPlayers;
  116.     FCalledDoOpen: Boolean;
  117.     FOnAddPlayer: TDXPlayEvent;
  118.     FOnClose: TNotifyEvent;
  119.     FOnDeletePlayer: TDXPlayEvent;
  120.     FOnMessage: TDXPlayMessageEvent;
  121.     FOnOpen: TNotifyEvent;
  122.     FOnSendComplete: TDXPlaySendCompleteEvent;
  123.     FOnSessionLost: TNotifyEvent;
  124.     FOpened: Boolean;
  125.     FRecvEvent: array[0..1] of THandle;
  126.     FRecvThread: TThread;
  127.     FInThread: Boolean;
  128.     FProviderName: string;
  129.     FProviders: TStrings;
  130.     FSessionName: string;
  131.     FSessions: TStrings;
  132.     FReadSessioned: Boolean;
  133.     FModemSetting: TDXPlayModemSetting;
  134.     FTCPIPSetting: TDXPlayTCPIPSetting;
  135.     FAsync: Boolean;
  136.     FAsyncSupported: Boolean;
  137.     procedure ChangeDPlay;
  138.     procedure CreateDPlayWithoutDialog(out DPlay:
  139.      //{$IfDef DX7}
  140.      IDirectPlay4A;
  141.      //{$Else}IDirectPlay8Address{$EndIf};
  142.       const ProviderName: string);
  143.     function OpenDPlayWithLobby(out Name: string): Boolean;
  144.     function OpenDPlayWithoutLobby(out Name: string): Boolean;
  145.     function OpenDPlayWithoutLobby2(const NewSession: Boolean; const ProviderName, SessionName, PlayerName: string): Boolean;
  146.     procedure Open_(NameS: string);
  147.     procedure ReceiveMessage;
  148.     function GetProviders: TStrings;
  149.     function GetSessionsPty: TStrings;
  150.     procedure ClearSessionList;
  151.     procedure SetGUID(const Value: string);
  152.     procedure SetModemSetting(Value: TDXPlayModemSetting);
  153.     procedure SetProviderName(const Value: string);
  154.     procedure SetTCPIPSetting(Value: TDXPlayTCPIPSetting);
  155.   protected
  156.     procedure DoAddPlayer(Player: TDXPlayPlayer); virtual;
  157.     procedure DoClose; virtual;
  158.     procedure DoDeletePlayer(Player: TDXPlayPlayer); virtual;
  159.     procedure DoMessage(From: TDXPlayPlayer; Data: Pointer; DataSize: Integer); virtual;
  160.     procedure DoOpen; virtual;
  161.     procedure DoSessionLost; virtual;
  162.     procedure DoSendComplete(MessageID: DWORD; Result: TDXPlaySendCompleteResult;
  163.       SendTime: Integer); virtual;
  164.   public
  165.     constructor Create(AOwner: TComponent); override;
  166.     destructor Destroy; override;
  167.     procedure Close;
  168.     procedure Open;
  169.     procedure Open2(NewSession: Boolean; const SessionName, PlayerName: string);
  170.     function GetProviderNameFromGUID(const ProviderGUID: TGUID): string;
  171.     procedure GetSessions;
  172.     procedure SendMessage(ToID: TDPID; Data: Pointer; DataSize: Integer);
  173.     function SendMessageEx(ToID: TDPID; Data: Pointer; DataSize: Integer;
  174.       dwFlags: DWORD): DWORD;
  175.     property GUID: string read FGUID write SetGUID;
  176.     property IsHost: Boolean read FIsHost;
  177.     property LocalPlayer: TDXPlayPlayer read FLocalPlayer;
  178.     property MaxPlayers: Integer read FMaxPlayers write FMaxPlayers;
  179.     property OnAddPlayer: TDXPlayEvent read FOnAddPlayer write FOnAddPlayer;
  180.     property OnClose: TNotifyEvent read FOnClose write FOnClose;
  181.     property OnDeletePlayer: TDXPlayEvent read FOnDeletePlayer write FOnDeletePlayer;
  182.     property OnMessage: TDXPlayMessageEvent read FOnMessage write FOnMessage;
  183.     property OnOpen: TNotifyEvent read FOnOpen write FOnOpen;
  184.     property OnSendComplete: TDXPlaySendCompleteEvent read FOnSendComplete write FOnSendComplete;
  185.     property OnSessionLost: TNotifyEvent read FOnSessionLost write FOnSessionLost;
  186.     property Opened: Boolean read FOpened;
  187.     property Players: TDXPlayPlayers read FPlayers;
  188.     property ProviderName: string read FProviderName write SetProviderName;
  189.     property Providers: TStrings read GetProviders;
  190.     property SessionName: string read FSessionName;
  191.     property Sessions: TStrings read GetSessionsPty;
  192.     property ModemSetting: TDXPlayModemSetting read FModemSetting write SetModemSetting;
  193.     property TCPIPSetting: TDXPlayTCPIPSetting read FTCPIPSetting write SetTCPIPSetting;
  194.     property Async: Boolean read FAsync write FAsync;
  195.     property AsyncSupported: Boolean read FAsyncSupported;
  196.   end;
  197.  
  198.   TDXPlay = class(TCustomDXPlay)
  199.   published
  200.     property Async;
  201.     property GUID;
  202.     property MaxPlayers;
  203.     property ModemSetting;
  204.     property TCPIPSetting;
  205.     property OnAddPlayer;
  206.     property OnClose;
  207.     property OnDeletePlayer;
  208.     property OnMessage;
  209.     property OnOpen;
  210.     property OnSendComplete;
  211.     property OnSessionLost;
  212.   end;
  213.  
  214. function DXPlayMessageType(P: Pointer): DWORD;
  215.  
  216. function DXPlayStringToGUID(const S: string): TGUID;
  217. function DXDirectPlayCreate(const lpGUID: TGUID; out lplpDP:
  218.   //{$IfDef DX7}
  219.   IDirectPlay;
  220.   //{$Else}IDirectPlay8Server{$EndIf};
  221.   pUnk: IUnknown): HRESULT;
  222.  
  223. implementation
  224.  
  225. uses DXPlayFm, DXConsts;
  226.  
  227. function DXPlayMessageType(P: Pointer): DWORD;
  228. begin
  229.   Result := PDPMSG_GENERIC(P)^.dwType;
  230. end;
  231.  
  232. function DXPlayStringToGUID(const S: string): TGUID;
  233. var
  234.   ErrorCode: Integer;
  235. begin
  236.   ErrorCode := CLSIDFromString(PWideChar(WideString(S)), Result);
  237.   if ErrorCode<0 then
  238.     raise EDXPlayError.Create(WindowsErrorMsg(ErrorCode));
  239. end;
  240.  
  241. function GUIDToString(const ClassID: TGUID): string;
  242. var
  243.   ErrorCode: Integer;
  244.   P: PWideChar;
  245. begin
  246.   ErrorCode := StringFromCLSID(ClassID, P);
  247.   if ErrorCode<0 then
  248.     raise EDXPlayError.Create(WindowsErrorMsg(ErrorCode));
  249.   Result := P;
  250.   CoTaskMemFree(P);
  251. end;
  252.  
  253. function DXDirectPlayCreate(const lpGUID: TGUID; out lplpDP:
  254.   //{$IfDef DX7}
  255.   IDirectPlay;
  256.   //{$Else}IDirectPlay8Server{$EndIf};
  257.   pUnk: IUnknown): HRESULT;
  258. type
  259.   TDirectPlayCreate= function(const lpGUID: TGUID; out lplpDP: IDirectPlay; pUnk: IUnknown): HRESULT; stdcall;
  260. begin
  261.   Result := TDirectPlayCreate(DXLoadLibrary('DPlayX.dll', 'DirectPlayCreate'))
  262.     (lpGUID, lplpDP, pUnk);
  263. end;
  264. {$IFDEF UNICODE}
  265. function DXDirectPlayEnumerate(lpEnumDPCallback: TDPEnumDPCallbackW; lpContext: Pointer): HRESULT;
  266. type
  267.   TDirectPlayEnumerateW= function(lpEnumDPCallback: TDPEnumDPCallbackW; lpContext: Pointer): HRESULT; stdcall;
  268. begin
  269.   Result := TDirectPlayEnumerateW(DXLoadLibrary('DPlayX.dll', 'DirectPlayEnumerateW'))
  270.     (lpEnumDPCallback, lpContext);
  271. end;
  272.  
  273. function DXDirectPlayLobbyCreate(const lpguidSP: TGUID; out lplpDPL: IDirectPlayLobbyW;
  274.   lpUnk: IUnknown; lpData: Pointer; dwDataSize: DWORD): HRESULT;
  275. type
  276.   TDirectPlayLobbyCreateW = function(const lpguidSP: TGUID; out lplpDPL: IDirectPlayLobbyW;
  277.     lpUnk: IUnknown; lpData: Pointer; dwDataSize: DWORD): HRESULT; stdcall;
  278. begin
  279.   Result := TDirectPlayLobbyCreateW(DXLoadLibrary('DPlayX.dll', 'DirectPlayLobbyCreateW'))
  280.     (lpguidSP, lplpDPL, lpUnk, lpData, dwDataSize);
  281. end;
  282. {$ELSE}
  283. function DXDirectPlayEnumerate(lpEnumDPCallback: TDPEnumDPCallbackA; lpContext: Pointer): HRESULT;
  284. type
  285.   TDirectPlayEnumerateA= function(lpEnumDPCallback: TDPEnumDPCallbackA; lpContext: Pointer): HRESULT; stdcall;
  286. begin
  287.   Result := TDirectPlayEnumerateA(DXLoadLibrary('DPlayX.dll', 'DirectPlayEnumerateA'))
  288.     (lpEnumDPCallback, lpContext);
  289. end;
  290.  
  291. function DXDirectPlayLobbyCreate(const lpguidSP: TGUID; out lplpDPL: IDirectPlayLobbyA;
  292.   lpUnk: IUnknown; lpData: Pointer; dwDataSize: DWORD): HRESULT;
  293. type
  294.   TDirectPlayLobbyCreateA = function(const lpguidSP: TGUID; out lplpDPL: IDirectPlayLobbyA;
  295.     lpUnk: IUnknown; lpData: Pointer; dwDataSize: DWORD): HRESULT; stdcall;
  296. begin
  297.   Result := TDirectPlayLobbyCreateA(DXLoadLibrary('DPlayX.dll', 'DirectPlayLobbyCreateA'))
  298.     (lpguidSP, lplpDPL, lpUnk, lpData, dwDataSize);
  299. end;
  300. {$ENDIF}
  301. {  TDXPlayPlayers  }
  302.  
  303. constructor TDXPlayPlayers.Create;
  304. begin
  305.   inherited Create(TDXPlayPlayer);
  306. end;
  307.  
  308. function TDXPlayPlayers.Find(ID: TDPID): TDXPlayPlayer;
  309. var
  310.   i: Integer;
  311. begin
  312.   i := IndexOf(ID);
  313.   if i=-1 then
  314.     raise EDXPlayError.Create(SDXPlayPlayerNotFound);
  315.   Result := Players[i];
  316. end;
  317.  
  318. function TDXPlayPlayers.IndexOf(ID: TDPID): Integer;
  319. var
  320.   i: Integer;
  321. begin
  322.   for i:=0 to Count-1 do
  323.     if Players[i].FID=ID then
  324.     begin
  325.       Result := i;
  326.       Exit;
  327.     end;
  328.   Result := -1;
  329. end;
  330.  
  331. function TDXPlayPlayers.GetPlayer(Index: Integer): TDXPlayPlayer;
  332. begin
  333.   Result := TDXPlayPlayer(Items[Index]);
  334. end;
  335.  
  336. {  TDXPlayModemSetting  }
  337.  
  338. destructor TDXPlayModemSetting.Destroy;
  339. begin
  340.   FModemNames.Free;
  341.   inherited Destroy;
  342. end;
  343.  
  344. procedure TDXPlayModemSetting.Assign(Source: TPersistent);
  345. begin
  346.   if Source is TDXPlayModemSetting then
  347.   begin
  348.     FEnabled := TDXPlayModemSetting(Source).FEnabled;
  349.     FPhoneNumber := TDXPlayModemSetting(Source).FPhoneNumber;
  350.     FModemName := TDXPlayModemSetting(Source).FModemName;
  351.   end else
  352.     inherited Assign(Source);
  353. end;
  354.  
  355. function TDXPlayModemSetting.GetModemNames: TStrings;
  356.  
  357.   function EnumModemAddress(const guidDataType: TGUID;
  358.     dwDataSize: DWORD; lpData: Pointer; lpContext: Pointer): BOOL; stdcall;
  359.   begin
  360.     if CompareMem(@guidDataType, @DPAID_Modem, SizeOf(TGUID)) then
  361.       TStrings(lpContext).Add( PChar(lpData));
  362.     Result := True;
  363.   end;
  364.  
  365. var
  366.   {$IFDEF UNICODE}
  367.   Lobby1: IDirectPlayLobbyW;
  368.   Lobby: IDirectPlayLobby2W;
  369.   DPlay: IDirectPlay4W;
  370.   {$ELSE}
  371.   Lobby1: IDirectPlayLobbyA;
  372.   Lobby: IDirectPlayLobby2A;
  373.   DPlay: IDirectPlay4A;
  374.   {$ENDIF}
  375.   DPlay1: IDirectPlay;
  376.   lpAddress: Pointer;
  377.   dwAddressSize: DWORD;
  378. begin
  379.   if FModemNames=nil then
  380.   begin
  381.     FModemNames := TStringList.Create;
  382.     try
  383.       if DXDirectPlayLobbyCreate(PGUID(nil)^, Lobby1, nil, nil, 0)<>0 then
  384.         raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  385.       Lobby := Lobby1 as {$IFDEF UNICODE}IDirectPlayLobby2W{$ELSE}IDirectPlayLobby2A{$ENDIF};
  386.  
  387.       if DXDirectPlayCreate(DPSPGUID_MODEM, DPlay1, nil)<>0 then
  388.         raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  389.       DPlay := DPlay1 as {$IFDEF UNICODE}IDirectPlay4W{$ELSE}IDirectPlay4A{$ENDIF};
  390.  
  391.       {  get size of player address for all players  }
  392.       if DPlay.GetPlayerAddress(DPID_ALLPLAYERS, nil, dwAddressSize)<>DPERR_BUFFERTOOSMALL then
  393.         raise EDXPlayError.Create(SDXPlayModemListCannotBeAcquired);
  394.  
  395.       GetMem(lpAddress, dwAddressSize);
  396.       try
  397.         FillChar(lpAddress^, dwAddressSize, 0);
  398.  
  399.         {  get the address  }
  400.         if DPlay.GetPlayerAddress(DPID_ALLPLAYERS, lpAddress, dwAddressSize)<>0 then
  401.           raise EDXPlayError.Create(SDXPlayModemListCannotBeAcquired);
  402.  
  403.         {  get modem strings from address and put them in the combo box  }
  404.         if Lobby.EnumAddress(@EnumModemAddress, lpAddress^, dwAddressSize, FModemNames)<>0 then
  405.           raise EDXPlayError.Create(SDXPlayModemListCannotBeAcquired);
  406.       finally
  407.         FreeMem(lpAddress);
  408.       end;
  409.     except
  410.       FModemNames.Free; FModemNames := nil;
  411.       raise;
  412.     end;
  413.   end;
  414.  
  415.   Result := FModemNames;
  416. end;
  417.  
  418. {  TDXPlayTCPIPSetting  }
  419.  
  420. procedure TDXPlayTCPIPSetting.Assign(Source: TPersistent);
  421. begin
  422.   if Source is TDXPlayTCPIPSetting then
  423.   begin
  424.     FEnabled := TDXPlayTCPIPSetting(Source).FEnabled;
  425.     FHostName := TDXPlayTCPIPSetting(Source).FHostName;
  426.   end else
  427.     inherited Assign(Source);
  428. end;
  429.  
  430. {  TCustomDXPlay  }
  431.  
  432. constructor TCustomDXPlay.Create(AOwner: TComponent);
  433. begin
  434.   inherited Create(AOwner);
  435.   FPlayers := TDXPlayPlayers.Create;
  436.   FModemSetting := TDXPlayModemSetting.Create;
  437.   FTCPIPSetting := TDXPlayTCPIPSetting.Create;
  438.   FSessions := TStringList.Create;
  439.  
  440.   FGUID := GUIDToString(GUID_NULL);
  441.   FMaxPlayers := 0;
  442. end;
  443.  
  444. destructor TCustomDXPlay.Destroy;
  445. var
  446.   i: Integer;
  447. begin
  448.   Close;
  449.  
  450.   FPlayers.Free;
  451.  
  452.   if FProviders<>nil then
  453.   begin
  454.     for i:=0 to FProviders.Count-1 do
  455.       Dispose(PGUID(FProviders.Objects[i]));
  456.   end;
  457.   FProviders.Free;
  458.   FModemSetting.Free;
  459.   FTCPIPSetting.Free;
  460.   ClearSessionList;
  461.   FSessions.Free;
  462.   inherited Destroy;
  463. end;
  464.  
  465. type
  466.   TDXPlayRecvThread = class(TThread)
  467.   private
  468.     FDXPlay: TCustomDXPlay;
  469.     constructor Create(DXPlay: TCustomDXPlay);
  470.     destructor Destroy; override;
  471.     procedure Execute; override;
  472.   end;
  473.  
  474. constructor TDXPlayRecvThread.Create(DXPlay: TCustomDXPlay);
  475. begin
  476.   FDXPlay := DXPlay;
  477.  
  478.   FDXPlay.FRecvEvent[1] := CreateEvent(nil, False, False, nil);
  479.  
  480.   FreeOnTerminate := True;
  481.   inherited Create(True);
  482. end;
  483.  
  484. destructor TDXPlayRecvThread.Destroy;
  485. begin
  486.   FreeOnTerminate := False;
  487.   SetEvent(FDXPlay.FRecvEvent[1]);
  488.  
  489.   inherited Destroy;
  490.  
  491.   CloseHandle(FDXPlay.FRecvEvent[1]);
  492.  
  493.   FDXPlay.FRecvThread := nil;
  494.   FDXPlay.Close;
  495. end;
  496.  
  497. procedure TDXPlayRecvThread.Execute;
  498. begin
  499.   while WaitForMultipleObjects(2, @FDXPlay.FRecvEvent, False, INFINITE)=WAIT_OBJECT_0 do
  500.   begin
  501.     Synchronize(FDXPlay.ReceiveMessage);
  502.   end;
  503. end;
  504.  
  505. procedure TCustomDXPlay.ReceiveMessage;
  506. var
  507.   idFrom, idTo: DWORD;
  508.   hr: HRESULT;
  509.   lpvMsgBuffer: Pointer;
  510.   dwMsgBufferSize: DWORD;
  511.   Msg_CreatePlayerOrGroup: PDPMSG_CREATEPLAYERORGROUP;
  512.   Msg_DeletePlayerOrGroup: PDPMSG_DESTROYPLAYERORGROUP;
  513.   Msg_SendComplete: PDPMsg_SendComplete;
  514.   SendCompleteResult: TDXPlaySendCompleteResult;
  515.   Player: TDXPlayPlayer;
  516.   i: Integer;
  517. begin
  518.   FInThread := True;
  519.   try
  520.     try
  521.       lpvMsgBuffer := nil;
  522.       dwMsgBufferSize := 0;
  523.  
  524.       try
  525.         repeat
  526.           hr := FDPlay.Receive(idFrom, idTo, DPRECEIVE_ALL, lpvMsgBuffer, dwMsgBufferSize);
  527.  
  528.           if hr=DPERR_BUFFERTOOSMALL then
  529.           begin
  530.             ReAllocMem(lpvMsgBuffer, dwMsgBufferSize);
  531.             hr := FDPlay.Receive(idFrom, idTo, DPRECEIVE_ALL, lpvMsgBuffer, dwMsgBufferSize);
  532.           end;
  533.  
  534.           if (hr=0) and (dwMsgBufferSize>=SizeOf(TDPMSG_GENERIC)) then
  535.           begin
  536.             if idFrom=DPID_SYSMSG then
  537.             begin
  538.               {  System message  }
  539.               case PDPMSG_GENERIC(lpvMsgBuffer)^.dwType of
  540.                 DPSYS_CREATEPLAYERORGROUP:
  541.                   begin
  542.                     {  New player  }
  543.                     Msg_CreatePlayerOrGroup := lpvMsgBuffer;
  544.  
  545.                     if Msg_CreatePlayerOrGroup.DPID<>FLocalPlayer.FID then
  546.                     begin
  547.                       Player := TDXPlayPlayer.Create(Players);
  548.                       Player.FID := Msg_CreatePlayerOrGroup.DPID;
  549.                       Player.FRemotePlayer := True;
  550.  
  551.                       with Msg_CreatePlayerOrGroup.dpnName do
  552.                       begin
  553.                         {$IFDEF UNICODE}
  554.                         if lpszShortNameW<>nil then
  555.                           Player.FName := lpszShortNameW;
  556.                         {$ELSE}
  557.                         if lpszShortNameA<>nil then
  558.                           Player.FName := lpszShortNameA;
  559.                         {$ENDIF}
  560.                       end;
  561.  
  562.                       DoAddPlayer(Player);
  563.                     end;
  564.                   end;
  565.                 DPSYS_DESTROYPLAYERORGROUP:
  566.                   begin
  567.                     {  Player deletion  }
  568.                     Msg_DeletePlayerOrGroup := lpvMsgBuffer;
  569.  
  570.                     if Msg_DeletePlayerOrGroup.DPID<>FLocalPlayer.FID then
  571.                     begin
  572.                       i := Players.IndexOf(Msg_DeletePlayerOrGroup.DPID);
  573.                       if i<>-1 then
  574.                       begin
  575.                         Player := Players[i];
  576.                         DoDeletePlayer(Player);
  577.                         Player.Free;
  578.                       end;
  579.                     end;
  580.                   end;
  581.                 DPSYS_SESSIONLOST:
  582.                   begin
  583.                     {  The session was lost.  }
  584.                     DoSessionLost;
  585.                     Close;
  586.                   end;
  587.                 DPSYS_HOST:
  588.                   begin
  589.                     {  Here became a host.  }
  590.                     FIsHost := True;
  591.                   end;
  592.                 DPSYS_SENDCOMPLETE:
  593.                    begin
  594.                      { Send complete  }
  595.                      Msg_SendComplete := lpvMsgBuffer;
  596.                      if Msg_SendComplete.idFrom=FLocalPlayer.FID then
  597.                      begin
  598.                        case Msg_SendComplete.hr of
  599.                          DP_OK        : SendCompleteResult := crOk;
  600.                          DPERR_ABORTED: SendCompleteResult := crAbort;
  601.                          else           SendCompleteResult := crGeneric;
  602.                        end;
  603.  
  604.                        DoSendComplete(Msg_SendComplete^.dwMsgID, SendCompleteResult, Msg_SendComplete^.dwSendTime);
  605.                      end;
  606.                    end;
  607.               end;
  608.             end else
  609.             begin
  610.               {  Application definition message  }
  611.               DoMessage(Players.Find(idFrom), lpvMsgBuffer, dwMsgBufferSize);
  612.             end;
  613.           end;
  614.         until hr<>0;
  615.       finally
  616.         FreeMem(lpvMsgBuffer);
  617.       end;
  618.     except
  619.       on E: Exception do
  620.         Application.HandleException(E);
  621.     end;
  622.   finally
  623.     FInThread := False;
  624.   end;
  625. end;
  626.  
  627. procedure TCustomDXPlay.DoAddPlayer(Player: TDXPlayPlayer);
  628. begin
  629.   if Assigned(FOnAddPlayer) then FOnAddPlayer(Self, Player)
  630. end;
  631.  
  632. procedure TCustomDXPlay.DoClose;
  633. begin
  634.   if Assigned(FOnClose) then FOnClose(Self);
  635. end;
  636.  
  637. procedure TCustomDXPlay.DoDeletePlayer(Player: TDXPlayPlayer);
  638. begin
  639.   if Assigned(FOnDeletePlayer) then FOnDeletePlayer(Self, Player)
  640. end;
  641.  
  642. procedure TCustomDXPlay.DoMessage(From: TDXPlayPlayer; Data: Pointer; DataSize: Integer);
  643. begin
  644.   if Assigned(FOnMessage) then FOnMessage(Self, From, Data, DataSize);
  645. end;
  646.  
  647. procedure TCustomDXPlay.DoOpen;
  648. begin
  649.   if Assigned(FOnOpen) then FOnOpen(Self);
  650. end;
  651.  
  652. procedure TCustomDXPlay.DoSessionLost;
  653. begin
  654.   if Assigned(FOnSessionLost) then FOnSessionLost(Self);
  655. end;
  656.  
  657. procedure TCustomDXPlay.DoSendComplete(MessageID: DWORD; Result: TDXPlaySendCompleteResult;
  658.   SendTime: Integer);
  659. begin
  660.   if Assigned(FOnSendComplete) then FOnSendComplete(Self, MessageID, Result, SendTime);
  661. end;
  662.  
  663. function TCustomDXPlay.GetProviders: TStrings;
  664.  
  665.   function EnumProviderCallback(const lpguidSP: TGUID; lpSPName: {$IFDEF UNICODE}LPCTSTR{$ELSE}LPSTR{$ENDIF};
  666.       dwMajorVersion: DWORD; dwMinorVersion: DWORD; lpContext: Pointer):
  667.       BOOL; stdcall;
  668.   var
  669.     GUID: PGUID;
  670.   begin
  671.     GUID := New(PGUID);
  672.     Move(lpguidSP, GUID^, SizeOf(TGUID));
  673.     TStrings(lpContext).AddObject(lpSPName, TObject(GUID));
  674.     Result := True;
  675.   end;
  676.  
  677. begin
  678.   if FProviders=nil then
  679.   begin
  680.     FProviders := TStringList.Create;
  681.     try
  682.       DXDirectPlayEnumerate(@EnumProviderCallback, FProviders);
  683.     except
  684.       FProviders.Free; FProviders := nil;
  685.       raise;
  686.     end;
  687.   end;
  688.  
  689.   Result := FProviders;
  690. end;
  691.  
  692. procedure TCustomDXPlay.GetSessions;
  693.  
  694.   function EnumSessionsCallback(const lpThisSD: TDPSessionDesc2;
  695.     var lpdwTimeOut: DWORD; dwFlags: DWORD; lpContext: Pointer): BOOL; stdcall;
  696.   var
  697.     Guid: PGUID;
  698.   begin
  699.     if dwFlags and DPESC_TIMEDOUT<>0 then
  700.     begin
  701.       Result := False;
  702.       Exit;
  703.     end;
  704.  
  705.     Guid := New(PGUID);
  706.     Move(lpThisSD.guidInstance, Guid^, SizeOf(TGUID));
  707.     {$IFDEF UNICODE}
  708.     TStrings(lpContext).AddObject(lpThisSD.lpszSessionNameW, TObject(Guid));
  709.     {$ELSE}
  710.     TStrings(lpContext).AddObject(lpThisSD.lpszSessionNameA, TObject(Guid));
  711.     {$ENDIF}
  712.     Result := True;
  713.   end;
  714.  
  715. var
  716.   dpDesc: TDPSessionDesc2;
  717.   hr: HRESULT;
  718. begin
  719.   if FDPlay=nil then
  720.     raise EDXPlayError.Create(SDXPlayNotConnectedNow);
  721.  
  722.   ClearSessionList;
  723.  
  724.   FillChar(dpDesc, SizeOf(dpDesc), 0);
  725.   dpDesc.dwSize := SizeOf(dpDesc);
  726.   dpDesc.guidApplication := DXPlayStringToGUID(FGUID);
  727.  
  728.   hr := FDPlay.EnumSessions(dpDesc, 0, @EnumSessionsCallback, FSessions, DPENUMSESSIONS_AVAILABLE);
  729.   if hr=DPERR_USERCANCEL then Abort;
  730.   if hr<>0 then
  731.     raise EDXPlayError.Create(SDXPlaySessionListCannotBeAcquired);
  732.  
  733.   FReadSessioned := True;
  734. end;
  735.  
  736. function TCustomDXPlay.GetSessionsPty: TStrings;
  737. begin
  738.   if not FReadSessioned then GetSessions;
  739.   Result := FSessions;
  740. end;
  741.  
  742. function TCustomDXPlay.GetProviderNameFromGUID(const ProviderGUID: TGUID): string;
  743. var
  744.   i: Integer;
  745. begin
  746.   for i:=0 to Providers.Count-1 do
  747.     if CompareMem(PGUID(Providers.Objects[i]), @ProviderGUID, SizeOf(TGUID)) then
  748.     begin
  749.       Result := Providers[i];
  750.       Exit;
  751.     end;
  752.  
  753.   raise EDXPlayError.Create(SDXPlayProviderSpecifiedGUIDNotFound);
  754. end;
  755.  
  756. procedure TCustomDXPlay.CreateDPlayWithoutDialog(out DPlay: IDirectPlay4A; const ProviderName: string);
  757. var
  758.   i: Integer;
  759.   ProviderGUID: TGUID;
  760.   addressElements: array[0..15] of TDPCompoundAddressElement;
  761.   dwElementCount: Integer;
  762.   {$IFDEF UNICODE}
  763.   Lobby1: IDirectPlayLobbyW;
  764.   Lobby: IDirectPlayLobby2W;
  765.   {$ELSE}
  766.   Lobby1: IDirectPlayLobbyA;
  767.   Lobby: IDirectPlayLobby2A;
  768.   {$ENDIF}
  769.   lpAddress: Pointer;
  770.   dwAddressSize: DWORD;
  771. begin
  772.   i := Providers.IndexOf(ProviderName);
  773.   if i=-1 then
  774.     raise EDXPlayError.CreateFmt(SDXPlayProviderNotFound, [ProviderName]);
  775.   ProviderGUID := PGUID(Providers.Objects[i])^;
  776.  
  777.   {  DirectPlay address making  }
  778.   if DXDirectPlayLobbyCreate(PGUID(nil)^, Lobby1, nil, nil, 0)<>0 then
  779.     raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  780.   Lobby := Lobby1 as {$IFDEF UNICODE}IDirectPlayLobby2W{$ELSE}IDirectPlayLobby2A{$ENDIF};
  781.  
  782.   FillChar(addressElements, SizeOf(addressElements), 0);
  783.   dwElementCount := 0;
  784.  
  785.   addressElements[dwElementCount].guidDataType := DPAID_ServiceProvider;
  786.   addressElements[dwElementCount].dwDataSize := SizeOf(TGUID);
  787.   addressElements[dwElementCount].lpData := @ProviderGUID;
  788.   Inc(dwElementCount);
  789.  
  790.   if CompareMem(@ProviderGUID, @DPSPGUID_MODEM, SizeOf(TGUID)) and ModemSetting.Enabled then
  791.   begin
  792.     {  Modem  }
  793.     if ModemSetting.FModemName<>'' then
  794.     begin
  795.       addressElements[dwElementCount].guidDataType := DPAID_Modem;
  796.       addressElements[dwElementCount].dwDataSize := Length(ModemSetting.FModemName)+1;
  797.       addressElements[dwElementCount].lpData := PChar(ModemSetting.FModemName);
  798.       Inc(dwElementCount);
  799.     end;
  800.  
  801.     if ModemSetting.FPhoneNumber<>'' then
  802.     begin
  803.       addressElements[dwElementCount].guidDataType := DPAID_Phone;
  804.       addressElements[dwElementCount].dwDataSize := Length(ModemSetting.FPhoneNumber)+1;
  805.       addressElements[dwElementCount].lpData := PChar(ModemSetting.FPhoneNumber);
  806.       Inc(dwElementCount);
  807.     end;
  808.   end else
  809.   if CompareMem(@ProviderGUID, @DPSPGUID_TCPIP, SizeOf(TGUID)) and TCPIPSetting.Enabled then
  810.   begin
  811.     {  TCP/IP  }
  812.     if TCPIPSetting.FHostName<>'' then
  813.     begin
  814.       addressElements[dwElementCount].guidDataType := DPAID_INet;
  815.       addressElements[dwElementCount].dwDataSize := Length(TCPIPSetting.FHostName)+1;
  816.       addressElements[dwElementCount].lpData := PChar(TCPIPSetting.FHostName);
  817.       Inc(dwElementCount);
  818.     end;
  819.  
  820.     if TCPIPSetting.Port<>0 then
  821.     begin
  822.       addressElements[dwElementCount].guidDataType := DPAID_INetPort;
  823.       addressElements[dwElementCount].dwDataSize := SizeOf(TCPIPSetting.FPort);
  824.       addressElements[dwElementCount].lpData := @TCPIPSetting.FPort;
  825.       Inc(dwElementCount);
  826.     end;
  827.   end;
  828.  
  829.   if Lobby.CreateCompoundAddress(addressElements[0], dwElementCount, nil, dwAddressSize)<>DPERR_BUFFERTOOSMALL then
  830.     raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  831.  
  832.   GetMem(lpAddress, dwAddressSize);
  833.   try
  834.     FillChar(lpAddress^, dwAddressSize, 0);
  835.  
  836.     if Lobby.CreateCompoundAddress(addressElements[0], dwElementCount, lpAddress, dwAddressSize)<>0 then
  837.       raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  838.  
  839.     {  DirectPlay initialization  }
  840.     if CoCreateInstance(CLSID_DirectPlay, nil, CLSCTX_INPROC_SERVER, IID_IDirectPlay4A, DPlay)<>0 then
  841.       raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  842.     try
  843.       {  DirectPlay address initialization  }
  844.       if DPlay.InitializeConnection(lpAddress, 0)<>0 then
  845.         raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  846.     except
  847.       DPlay := nil;
  848.       raise;
  849.     end;
  850.   finally
  851.     FreeMem(lpAddress);
  852.   end;
  853. end;
  854.  
  855. procedure TCustomDXPlay.ClearSessionList;
  856. var
  857.   i: Integer;
  858. begin
  859.   FReadSessioned := False;
  860.   for i:=0 to FSessions.Count-1 do
  861.     Dispose(PGUID(FSessions.Objects[i]));
  862.   FSessions.Clear;
  863. end;
  864.  
  865. procedure TCustomDXPlay.Open;
  866. var
  867.   PlayerName: string;
  868. begin
  869.   Close;
  870.   try
  871.     if not OpenDPlayWithLobby(PlayerName) then
  872.     begin
  873.       if not OpenDPlayWithoutLobby(PlayerName) then
  874.         Abort;
  875.     end;
  876.  
  877.     Open_(PlayerName);
  878.   except
  879.     Close;
  880.     raise;
  881.   end;
  882. end;
  883.  
  884. procedure TCustomDXPlay.Open2(NewSession: Boolean; const SessionName, PlayerName: string);
  885. begin
  886.   if not OpenDPlayWithoutLobby2(NewSession, ProviderName, SessionName, PlayerName) then
  887.     Abort;
  888.  
  889.   Open_(PlayerName);
  890. end;
  891.  
  892. procedure TCustomDXPlay.Open_(NameS: string);
  893.  
  894.   function EnumPlayersCallback2(TDPID: TDPID; dwPlayerType: DWORD;
  895.     const lpName: TDPName; dwFlags: DWORD; lpContext: Pointer): BOOL;
  896.     stdcall;
  897.   var
  898.     Player: TDXPlayPlayer;
  899.   begin
  900.     Player := TDXPlayPlayer.Create(TCustomDXPlay(lpContext).Players);
  901.     Player.FID := TDPID;
  902.     Player.FRemotePlayer := True;
  903.  
  904.     with lpName do
  905.     begin
  906.       {$IFDEF UNICODE}
  907.       if lpszShortNameW<>nil then
  908.         Player.FName := lpszShortNameW;
  909.       {$ELSE}
  910.       if lpszShortNameA<>nil then
  911.         Player.FName := lpszShortNameA;
  912.       {$ENDIF}
  913.     end;
  914.  
  915.     Result := True;
  916.   end;
  917.  
  918. var
  919.   Name2: array[0..1023] of Char;
  920.   Name: TDPName;
  921. begin
  922.   if FOpened then Close;
  923.   FOpened := True;
  924.   try
  925.     {  Player making  }
  926.     StrLCopy(@Name2, PChar(NameS), SizeOf(Name2));
  927.  
  928.     Name.lpszShortNameA := @Name2;
  929.     Name.lpszLongNameA := nil;
  930.  
  931.     FRecvEvent[0] := CreateEvent(nil, False, False, nil);
  932.  
  933.     FLocalPlayer := TDXPlayPlayer.Create(FPlayers);
  934.     FLocalPlayer.FName := NameS;
  935.  
  936.     if FDPlay.CreatePlayer(FLocalPlayer.FID, @Name, FRecvEvent[0], nil, 0, 0)<>DP_OK then
  937.       raise EDXPlayError.CreateFmt(SCannotOpened, [FSessionName]);
  938.  
  939.     {  Player enumeration  }
  940.     FDPlay.EnumPlayers(PGUID(nil), @EnumPlayersCallback2, Self, DPENUMPLAYERS_REMOTE);
  941.  
  942.     FIsHost := FPlayers.Count=1;
  943.  
  944.     FCalledDoOpen := True; DoOpen;
  945.     DoAddPlayer(FLocalPlayer);
  946.  
  947.     {  Thread start  }
  948.     FRecvThread := TDXPlayRecvThread.Create(Self);
  949.     FRecvThread.{$IFDEF VER14UP}Start{$ELSE}Resume{$ENDIF};
  950.   except
  951.     Close;
  952.     raise;
  953.   end;
  954. end;
  955.  
  956. procedure TCustomDXPlay.ChangeDPlay;
  957. var
  958.   caps: TDPCAPS;
  959. begin
  960.   FAsyncSupported := False;
  961.   if FDPlay<>nil then
  962.   begin
  963.     FillChar(caps, SizeOf(caps), 0);
  964.     caps.dwSize := SizeOf(caps);
  965.     FDPlay.GetCaps(caps, 0);
  966.  
  967.     FAsyncSupported := caps.dwFlags and DPCAPS_ASYNCSUPPORTED<>0;
  968.   end;
  969. end;
  970.  
  971. function TCustomDXPlay.OpenDPlayWithLobby(out Name: string): Boolean;
  972. var
  973.   DPlay1: IDirectPlay2;
  974.   {$IFDEF UNICODE}
  975.   Lobby: IDirectPlayLobbyW;
  976.   {$ELSE}
  977.   Lobby: IDirectPlayLobbyA;
  978.   {$ENDIF}
  979.   dwSize: DWORD;
  980.   ConnectionSettings: PDPLConnection;
  981. begin
  982.   Result := False;
  983.  
  984.   if DXDirectPlayLobbyCreate(PGUID(nil)^, Lobby, nil, nil, 0)<>0 then
  985.     Exit;
  986.  
  987.   if Lobby.GetConnectionSettings(0, PDPLConnection(nil), dwSize)<>DPERR_BUFFERTOOSMALL then
  988.     Exit;
  989.  
  990.   GetMem(ConnectionSettings, dwSize);
  991.   try
  992.     if Lobby.GetConnectionSettings(0, ConnectionSettings, dwSize)<>0 then
  993.       Exit;
  994.  
  995.     with ConnectionSettings^.lpSessionDesc^ do
  996.     begin
  997.       dwFlags := DPSESSION_MIGRATEHOST or DPSESSION_KEEPALIVE or DPSESSION_DIRECTPLAYPROTOCOL;
  998.       dwMaxPlayers := FMaxPlayers;
  999.     end;
  1000.  
  1001.     if Lobby.SetConnectionSettings(0, 0, ConnectionSettings^)<>0 then
  1002.       Exit;
  1003.  
  1004.     if Lobby.Connect(0, DPlay1, nil)<>0 then
  1005.       Exit;
  1006.     FDPlay := DPlay1 as IDirectPlay4A;
  1007.     ChangeDPlay;
  1008.  
  1009.     with ConnectionSettings.lpSessionDesc^ do
  1010.     begin
  1011.       {$IFDEF UNICODE}
  1012.       if lpszSessionNameW<>nil then
  1013.         FSessionName := lpszSessionNameW;
  1014.       {$ELSE}
  1015.       if lpszSessionNameA<>nil then
  1016.         FSessionName := lpszSessionNameA;
  1017.       {$ENDIF}
  1018.     end;
  1019.  
  1020.     with ConnectionSettings.lpPlayerName^ do
  1021.     begin
  1022.       {$IFDEF UNICODE}
  1023.       if lpszShortNameW<>nil then
  1024.         Name := lpszShortNameW;
  1025.       {$ELSE}
  1026.       if lpszShortNameA<>nil then
  1027.         Name := lpszShortNameA;
  1028.       {$ENDIF}
  1029.     end;
  1030.   finally
  1031.     FreeMem(ConnectionSettings);
  1032.   end;
  1033.  
  1034.   Result := True;
  1035. end;
  1036.  
  1037. function TCustomDXPlay.OpenDPlayWithoutLobby(out Name: string): Boolean;
  1038. var
  1039.   Form: TDelphiXDXPlayForm;
  1040. begin
  1041.   Form := TDelphiXDXPlayForm.Create(Application);
  1042.   try
  1043.     Form.DXPlay := Self;
  1044.     Form.ShowModal;
  1045.  
  1046.     Result := Form.Tag<>0;
  1047.  
  1048.     FDPlay := Form.DPlay;
  1049.     ChangeDPlay;
  1050.  
  1051.     Name := Form.PlayerName;
  1052.     FProviderName := Form.ProviderName;
  1053.     FSessionName := Form.SessionName;
  1054.   finally
  1055.     Form.Free;
  1056.   end;
  1057. end;
  1058.  
  1059. function TCustomDXPlay.OpenDPlayWithoutLobby2(const NewSession: Boolean;
  1060.   const ProviderName, SessionName, PlayerName: string): Boolean;
  1061. var
  1062.   dpDesc: TDPSessionDesc2;
  1063.   i: Integer;
  1064.   hr: HRESULT;
  1065. begin
  1066.   Result := False;
  1067.  
  1068.   if FDPlay=nil then
  1069.     raise EDXPlayError.Create(SDXPlayNotConnectedNow);
  1070.  
  1071.   if SessionName='' then
  1072.     raise EDXPlayError.Create(SDXPlaySessionNameIsNotSpecified);
  1073.  
  1074.   if PlayerName='' then
  1075.     raise EDXPlayError.Create(SDXPlayPlayerNameIsNotSpecified);
  1076.  
  1077.   if NewSession then
  1078.   begin
  1079.     {  Session connection  }
  1080.     FillChar(dpDesc, SizeOf(dpDesc), 0);
  1081.     dpDesc.dwSize := SizeOf(dpDesc);
  1082.     dpDesc.dwFlags := DPSESSION_MIGRATEHOST or DPSESSION_KEEPALIVE;
  1083.     {$IFDEF UNICODE}
  1084.     dpDesc.lpszSessionNameW := {$IFDEF VER12UP}PChar{$ELSE}PWideChar{$ENDIF}(SessionName);
  1085.     {$ELSE}
  1086.     dpDesc.lpszSessionNameA := PAnsiChar(SessionName);
  1087.     {$ENDIF}
  1088.     dpDesc.guidApplication := DXPlayStringToGUID(GUID);
  1089.     dpDesc.dwMaxPlayers := MaxPlayers;
  1090.  
  1091.     hr := FDPlay.Open(dpDesc, DPOPEN_CREATE);
  1092.     if hr=DPERR_USERCANCEL then Exit;
  1093.     if hr<>0 then
  1094.       raise EDXPlayError.CreateFmt(SDXPlaySessionCannotOpened, [FSessionName]);
  1095.   end else
  1096.   begin
  1097.     {  Session connection  }
  1098.     {  Enum session  }
  1099.     i := Sessions.IndexOf(SessionName);
  1100.     if i=-1 then raise EDXPlayError.CreateFmt(SDXPlaySessionNotFound, [SessionName]);
  1101.  
  1102.     FillChar(dpDesc, SizeOf(dpDesc), 0);
  1103.     dpDesc.dwSize := SizeOf(dpDesc);
  1104.     dpDesc.guidInstance := PGUID(Sessions.Objects[i])^;
  1105.     dpDesc.guidApplication := DXPlayStringToGUID(GUID);
  1106.  
  1107.     hr := FDPlay.Open(dpDesc, DPOPEN_JOIN);
  1108.     if hr=DPERR_USERCANCEL then Exit;
  1109.     if hr<>0 then
  1110.       raise EDXPlayError.CreateFmt(SDXPlaySessionCannotOpened, [FSessionName]);
  1111.   end;
  1112.  
  1113.   Result := True;
  1114.  
  1115.   FSessionName := SessionName;
  1116. end;
  1117.  
  1118. procedure TCustomDXPlay.Close;
  1119. begin
  1120.   FOpened := False;
  1121.   FReadSessioned := False;
  1122.  
  1123.   try
  1124.     if FCalledDoOpen then
  1125.     begin
  1126.       FCalledDoOpen := False;
  1127.       DoClose;
  1128.     end;
  1129.   finally
  1130.     if FDPlay<>nil then
  1131.     begin
  1132.       if FLocalPlayer<>nil then FDPlay.DestroyPlayer(FLocalPlayer.FID);
  1133.       FDPlay.Close;
  1134.     end;
  1135.  
  1136.     FProviderName := '';
  1137.     FSessionName := '';
  1138.     FAsyncSupported := False;
  1139.  
  1140.     ClearSessionList;
  1141.  
  1142.     FDPlay := nil;
  1143.     ChangeDPlay;
  1144.  
  1145.     if FInThread then
  1146.       SetEvent(FRecvEvent[1])
  1147.     else
  1148.       FRecvThread.Free;
  1149.  
  1150.     CloseHandle(FRecvEvent[0]); FRecvEvent[0] := 0;
  1151.  
  1152.     FPlayers.Clear;
  1153.  
  1154.     FLocalPlayer := nil;
  1155.   end;
  1156. end;
  1157.  
  1158. procedure TCustomDXPlay.SendMessage(ToID: TDPID; Data: Pointer; DataSize: Integer);
  1159. begin
  1160.   if not Opened then Exit;
  1161.  
  1162.   if DataSize<SizeOf(TDPMSG_GENERIC) then
  1163.     raise EDXPlayError.Create(SDXPlayMessageIllegal);
  1164.  
  1165.   if ToID=FLocalPlayer.ID then
  1166.   begin
  1167.     {  Message to me  }
  1168.     DoMessage(FLocalPlayer, Data, DataSize);
  1169.   end else
  1170.   if FAsync and FAsyncSupported then
  1171.     FDPlay.SendEx(FLocalPlayer.ID, ToID, DPSEND_GUARANTEED or DPSEND_ASYNC, Data, DataSize, 0, 0, nil, nil)
  1172.   else
  1173.     FDPlay.Send(FLocalPlayer.ID, ToID, DPSEND_GUARANTEED, Data^, DataSize);
  1174. end;
  1175.  
  1176. function TCustomDXPlay.SendMessageEx(ToID: TDPID; Data: Pointer; DataSize: Integer;
  1177.   dwFlags: DWORD): DWORD;
  1178. begin
  1179.   if not Opened then Exit;
  1180.  
  1181.   if DataSize<SizeOf(TDPMSG_GENERIC) then
  1182.     raise EDXPlayError.Create(SDXPlayMessageIllegal);
  1183.  
  1184.   Result := 0;
  1185.   if ToID=FLocalPlayer.ID then
  1186.   begin
  1187.     {  Ž©•ªˆ¶‚̃ƒbƒZ[ƒW  }
  1188.     DoMessage(FLocalPlayer, Data, DataSize);
  1189.   end else
  1190.     FDPlay.SendEx(FLocalPlayer.ID, ToID, dwFlags, Data, DataSize,
  1191.       0, 0, nil, @Result); // 0 ˆÈŠO‚̓Tƒ|[ƒg‚µ‚È‚¢ƒfƒoƒCƒX‚ ‚é‚Ì‚ÅŽg‚í‚È‚¢
  1192. end;
  1193.  
  1194. procedure TCustomDXPlay.SetGUID(const Value: string);
  1195. begin
  1196.   if Value<>FGUID then
  1197.   begin
  1198.     if Value='' then
  1199.     begin
  1200.       FGUID := GUIDToString(GUID_NULL);
  1201.     end else
  1202.     begin
  1203.       FGUID := GUIDToString(DXPlayStringToGUID(Value));
  1204.     end;
  1205.   end;
  1206. end;
  1207.  
  1208. procedure TCustomDXPlay.SetModemSetting(Value: TDXPlayModemSetting);
  1209. begin
  1210.   FModemSetting.Assign(Value);
  1211. end;
  1212.  
  1213. procedure TCustomDXPlay.SetProviderName(const Value: string);
  1214. begin
  1215.   Close;
  1216.   FProviderName := Value;
  1217.   if FProviderName='' then Exit;
  1218.   try
  1219.     CreateDPlayWithoutDialog(FDPlay, Value);
  1220.   except
  1221.     FProviderName := '';
  1222.     raise;
  1223.   end;
  1224. end;
  1225.  
  1226. procedure TCustomDXPlay.SetTCPIPSetting(Value: TDXPlayTCPIPSetting);
  1227. begin
  1228.   FTCPIPSetting.Assign(Value);
  1229. end;
  1230.  
  1231. initialization
  1232.   CoInitialize(nil);
  1233. finalization
  1234.   CoUninitialize;
  1235. end.