home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / DELPHIX.ZIP / Source / DXPlay.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-10-06  |  28.4 KB  |  1,017 lines

  1. unit DXPlay;
  2.  
  3. interface
  4.  
  5. {$INCLUDE DelphiXcfg.inc}
  6.  
  7. uses
  8.   Windows, SysUtils, Classes, Forms, DXClass, ActiveX, DirectX, DXETable;
  9.                                                                         
  10. type
  11.  
  12.   {  TDXPlayPlayer  }
  13.  
  14.   TDXPlayPlayer = class(TCollectionItem)
  15.   private
  16.     FData: Pointer;
  17.     FID: DPID;
  18.     FName: string;
  19.     FRemotePlayer: Boolean;
  20.   public
  21.     property Data: Pointer read FData write FData;
  22.     property ID: DPID read FID;
  23.     property Name: string read FName;
  24.     property RemotePlayer: Boolean read FRemotePlayer;
  25.   end;
  26.  
  27.   {  TDXPlayPlayers  }
  28.  
  29.   TDXPlayPlayers = class(TCollection)
  30.   private
  31.     function GetPlayer(Index: Integer): TDXPlayPlayer;
  32.   public
  33.     constructor Create;
  34.     function Find(ID: DPID): TDXPlayPlayer;
  35.     function IndexOf(ID: DPID): Integer;
  36.     property Players[Index: Integer]: TDXPlayPlayer read GetPlayer; default;
  37.   end;
  38.  
  39.   {  TDXPlayModemSetting  }
  40.  
  41.   TDXPlayModemSetting = class(TPersistent)
  42.   private
  43.     FEnabled: Boolean;
  44.     FPhoneNumber: string;
  45.     FModemName: string;
  46.     FModemNames: TStrings;
  47.     function GetModemNames: TStrings;
  48.   public
  49.     destructor Destroy; override;
  50.     property Enabled: Boolean read FEnabled write FEnabled;
  51.     property PhoneNumber: string read FPhoneNumber write FPhoneNumber;
  52.     property ModemName: string read FModemName write FModemName;
  53.     property ModemNames: TStrings read GetModemNames;
  54.   end;
  55.  
  56.   {  TDXPlayTCPIPSetting  }
  57.  
  58.   TDXPlayTCPIPSetting = class(TPersistent)
  59.   private
  60.     FEnabled: Boolean;
  61.     FHostName: string;
  62.   public
  63.     property Enabled: Boolean read FEnabled write FEnabled;
  64.     property HostName: string read FHostName write FHostName;
  65.   end;
  66.  
  67.   {  EDXPlayError  }
  68.  
  69.   EDXPlayError = class(Exception);
  70.  
  71.   {  TCustomDXPlay  }
  72.  
  73.   TDXPlayEvent = procedure(Sender: TObject; Player: TDXPlayPlayer) of object;
  74.  
  75.   TDXPlayMessageEvent = procedure(Sender: TObject; From: TDXPlayPlayer;
  76.     Data: Pointer; DataSize: Integer) of object;
  77.  
  78.   TCustomDXPlay = class(TComponent)
  79.   private
  80.     FDPlay: IDirectPlay3A;
  81.     FGUID: string;
  82.     FIsHost: Boolean;
  83.     FLocalPlayer: TDXPlayPlayer;
  84.     FMaxPlayers: Integer;
  85.     FPlayers: TDXPlayPlayers;
  86.     FCalledDoOpen: Boolean;
  87.     FOnAddPlayer: TDXPlayEvent;
  88.     FOnClose: TNotifyEvent;
  89.     FOnDeletePlayer: TDXPlayEvent;
  90.     FOnMessage: TDXPlayMessageEvent;
  91.     FOnOpen: TNotifyEvent;
  92.     FOnSessionLost: TNotifyEvent;
  93.     FOpened: Boolean;
  94.     FRecvEvent: array[0..1] of THandle;
  95.     FRecvThread: TThread;
  96.     FInThread: Boolean;
  97.     FProviderName: string;
  98.     FProviders: TStrings;
  99.     FSessionName: string;
  100.     FSessions: TStrings;
  101.     FReadSessioned: Boolean;
  102.     FModemSetting: TDXPlayModemSetting;
  103.     FTCPIPSetting: TDXPlayTCPIPSetting;
  104.     procedure CreateDPlayWithoutDialog(out DPlay: IDirectPlay3A; const ProviderName: string);
  105.     function OpenDPlayWithLobby(out Name: string): Boolean;
  106.     function OpenDPlayWithoutLobby(out Name: string): Boolean;
  107.     function OpenDPlayWithoutLobby2(const NewSession: Boolean; const ProviderName, SessionName, PlayerName: string): Boolean;
  108.     procedure Open_(NameS: string);
  109.     procedure ReceiveMessage;
  110.     procedure SendMessageEx(ToID: DPID; Data: Pointer; DataSize: Integer; dwFlags: DWORD);
  111.     function GetProviders: TStrings;
  112.     function GetSessionsPty: TStrings;
  113.     procedure ClearSessionList;
  114.     procedure SetGUID(const Value: string);
  115.     procedure SetProviderName(const Value: string);
  116.   protected
  117.     procedure DoAddPlayer(Player: TDXPlayPlayer); virtual;
  118.     procedure DoClose; virtual;
  119.     procedure DoDeletePlayer(Player: TDXPlayPlayer); virtual;
  120.     procedure DoMessage(From: TDXPlayPlayer; Data: Pointer; DataSize: Integer); virtual;
  121.     procedure DoOpen; virtual;
  122.     procedure DoSessionLost; virtual;
  123.   public
  124.     constructor Create(AOwner: TComponent); override;
  125.     destructor Destroy; override;
  126.     procedure Close;
  127.     procedure Open;
  128.     procedure Open2(const NewSession: Boolean; const SessionName, PlayerName: string);
  129.     function GetProviderNameFromGUID(const ProviderGUID: TGUID): string;
  130.     procedure GetSessions;
  131.     procedure SendMessage(ToID: DPID; Data: Pointer; DataSize: Integer);
  132.     property GUID: string read FGUID write SetGUID;
  133.     property IsHost: Boolean read FIsHost;
  134.     property LocalPlayer: TDXPlayPlayer read FLocalPlayer;
  135.     property MaxPlayers: Integer read FMaxPlayers write FMaxPlayers;
  136.     property OnAddPlayer: TDXPlayEvent read FOnAddPlayer write FOnAddPlayer;
  137.     property OnClose: TNotifyEvent read FOnClose write FOnClose;
  138.     property OnDeletePlayer: TDXPlayEvent read FOnDeletePlayer write FOnDeletePlayer;
  139.     property OnMessage: TDXPlayMessageEvent read FOnMessage write FOnMessage;
  140.     property OnOpen: TNotifyEvent read FOnOpen write FOnOpen;
  141.     property OnSessionLost: TNotifyEvent read FOnSessionLost write FOnSessionLost;
  142.     property Opened: Boolean read FOpened;
  143.     property Players: TDXPlayPlayers read FPlayers;
  144.     property ProviderName: string read FProviderName write SetProviderName;
  145.     property Providers: TStrings read GetProviders;
  146.     property SessionName: string read FSessionName;
  147.     property Sessions: TStrings read GetSessionsPty;
  148.     property ModemSetting: TDXPlayModemSetting read FModemSetting;
  149.     property TCPIPSetting: TDXPlayTCPIPSetting read FTCPIPSetting;
  150.   end;
  151.  
  152.   TDXPlay = class(TCustomDXPlay)
  153.   published
  154.     property GUID;
  155.     property MaxPlayers;
  156.     property OnAddPlayer;
  157.     property OnClose;
  158.     property OnDeletePlayer;
  159.     property OnMessage;
  160.     property OnOpen;
  161.     property OnSessionLost;
  162.   end;
  163.  
  164. function DXPlayMessageType(P: Pointer): DWORD;
  165.  
  166. function DXPlayStringToGUID(const S: string): TGUID;
  167. function DXDirectPlayCreate(const lpGUID: TGUID; out lplpDP: IDirectPlay;
  168.   pUnk: IUnknown): HRESULT;
  169.  
  170. implementation
  171.  
  172. uses DXPlayFm, DXConsts;
  173.  
  174. function DXPlayMessageType(P: Pointer): DWORD;
  175. begin
  176.   Result := LPDPMSG_GENERIC(P)^.dwType;
  177. end;
  178.  
  179. function DXPlayStringToGUID(const S: string): TGUID;
  180. var
  181.   ErrorCode: Integer;
  182. begin
  183.   ErrorCode := CLSIDFromString(PWideChar(WideString(S)), Result);
  184.   if ErrorCode<0 then
  185.     raise EDXPlayError.Create(WindowsErrorMsg(ErrorCode));
  186. end;
  187.  
  188. function GUIDToString(const ClassID: TGUID): string;
  189. var
  190.   ErrorCode: Integer;
  191.   P: PWideChar;
  192. begin
  193.   ErrorCode := StringFromCLSID(ClassID, P);
  194.   if ErrorCode<0 then
  195.     raise EDXPlayError.Create(WindowsErrorMsg(ErrorCode));
  196.   Result := P;
  197.   CoTaskMemFree(P);
  198. end;
  199.  
  200. function DXDirectPlayCreate(const lpGUID: TGUID; out lplpDP: IDirectPlay;
  201.   pUnk: IUnknown): HRESULT;
  202. type
  203.   TDirectPlayCreate= function(const lpGUID: TGUID; out lplpDP: IDirectPlay; pUnk: IUnknown): HRESULT; stdcall;
  204. begin
  205.   Result := TDirectPlayCreate(DXLoadLibrary('DPlayX.dll', 'DirectPlayCreate'))
  206.     (lpGUID, lplpDP, pUnk);
  207. end;
  208.  
  209. function DXDirectPlayEnumerateA(lpEnumDPCallback: LPDPENUMDPCALLBACKA; lpContext: Pointer): HRESULT;
  210. type
  211.   TDirectPlayEnumerateA= function(lpEnumDPCallback: LPDPENUMDPCALLBACKA; lpContext: Pointer): HRESULT; stdcall;
  212. begin
  213.   Result := TDirectPlayEnumerateA(DXLoadLibrary('DPlayX.dll', 'DirectPlayEnumerateA'))
  214.     (lpEnumDPCallback, lpContext);
  215. end;
  216.  
  217. function DXDirectPlayLobbyCreateA(const lpguidSP: TGUID; out lplpDPL: IDirectPlayLobbyA;
  218.     lpUnk: IUnknown; lpData: Pointer; dwDataSize: DWORD): HRESULT;
  219. type
  220.   TDirectPlayLobbyCreateA = function(const lpguidSP: TGUID; out lplpDPL: IDirectPlayLobbyA;
  221.       lpUnk: IUnknown; lpData: Pointer; dwDataSize: DWORD): HRESULT; stdcall;
  222. begin
  223.   Result := TDirectPlayLobbyCreateA(DXLoadLibrary('DPlayX.dll', 'DirectPlayLobbyCreateA'))
  224.     (lpguidSP, lplpDPL, lpUnk, lpData, dwDataSize);
  225. end;
  226.  
  227. {  TDXPlayPlayers  }
  228.  
  229. constructor TDXPlayPlayers.Create;
  230. begin
  231.   inherited Create(TDXPlayPlayer);
  232. end;
  233.  
  234. function TDXPlayPlayers.Find(ID: DPID): TDXPlayPlayer;
  235. var
  236.   i: Integer;
  237. begin
  238.   i := IndexOf(ID);
  239.   if i=-1 then
  240.     raise EDXPlayError.Create(SDXPlayPlayerNotFound);
  241.   Result := Players[i];
  242. end;
  243.  
  244. function TDXPlayPlayers.IndexOf(ID: DPID): Integer;
  245. var
  246.   i: Integer;
  247. begin
  248.   for i:=0 to Count-1 do
  249.     if Players[i].FID=ID then
  250.     begin
  251.       Result := i;
  252.       Exit;
  253.     end;
  254.   Result := -1;
  255. end;
  256.  
  257. function TDXPlayPlayers.GetPlayer(Index: Integer): TDXPlayPlayer;
  258. begin
  259.   Result := TDXPlayPlayer(Items[Index]);
  260. end;
  261.  
  262. {  TDXPlayModemSetting  }
  263.  
  264. destructor TDXPlayModemSetting.Destroy;
  265. begin
  266.   FModemNames.Free;
  267.   inherited Destroy;
  268. end;
  269.  
  270. function TDXPlayModemSetting.GetModemNames: TStrings;
  271.  
  272.   function EnumModemAddress(const guidDataType: TGUID;
  273.     dwDataSize: DWORD; lpData: Pointer; lpContext: Pointer): BOOL; stdcall;
  274.   begin
  275.     if CompareMem(@guidDataType, @DPAID_Modem, SizeOf(TGUID)) then
  276.       TStrings(lpContext).Add( PChar(lpData));
  277.     Result := True;
  278.   end;
  279.  
  280. var
  281.   Lobby1: IDirectPlayLobbyA;
  282.   Lobby: IDirectPlayLobby2A;
  283.   DPlay1: IDirectPlay;
  284.   DPlay: IDirectPlay3A;
  285.   lpAddress: Pointer;
  286.   dwAddressSize: DWORD;
  287. begin
  288.   if FModemNames=nil then
  289.   begin
  290.     FModemNames := TStringList.Create;
  291.     try
  292.       if DXDirectPlayLobbyCreateA(PGUID(nil)^, Lobby1, nil, nil, 0)<>0 then
  293.         raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  294.       Lobby := Lobby1 as IDirectPlayLobby2A;
  295.  
  296.       if DirectPlayCreate(DPSPGUID_MODEM, DPlay1, nil)<>0 then
  297.         raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  298.       DPlay := DPlay1 as IDirectPlay3A;
  299.  
  300.       {  get size of player address for all players  }
  301.       if DPlay.GetPlayerAddress(DPID_ALLPLAYERS, nil^, dwAddressSize)<>DPERR_BUFFERTOOSMALL then
  302.         raise EDXPlayError.Create(SDXPlayModemListCannotBeAcquired);
  303.  
  304.       GetMem(lpAddress, dwAddressSize);
  305.       try
  306.         FillChar(lpAddress^, dwAddressSize, 0);
  307.  
  308.         {  get the address  }
  309.         if DPlay.GetPlayerAddress(DPID_ALLPLAYERS, lpAddress^, dwAddressSize)<>0 then
  310.           raise EDXPlayError.Create(SDXPlayModemListCannotBeAcquired);
  311.  
  312.         {  get modem strings from address and put them in the combo box  }
  313.         if Lobby.EnumAddress(@EnumModemAddress, lpAddress^, dwAddressSize, FModemNames)<>0 then
  314.           raise EDXPlayError.Create(SDXPlayModemListCannotBeAcquired);
  315.       finally
  316.         FreeMem(lpAddress);
  317.       end;
  318.     except
  319.       FModemNames.Free; FModemNames := nil;
  320.       raise;
  321.     end;
  322.   end;
  323.  
  324.   Result := FModemNames;
  325. end;
  326.  
  327. {  TCustomDXPlay  }
  328.  
  329. constructor TCustomDXPlay.Create(AOwner: TComponent);
  330. begin
  331.   inherited Create(AOwner);
  332.   FPlayers := TDXPlayPlayers.Create;
  333.   FModemSetting := TDXPlayModemSetting.Create;
  334.   FTCPIPSetting := TDXPlayTCPIPSetting.Create;
  335.   FSessions := TStringList.Create;
  336.  
  337.   FGUID := GUIDToString(GUID_NULL);
  338.   FMaxPlayers := 0;
  339. end;
  340.  
  341. destructor TCustomDXPlay.Destroy;
  342. var
  343.   i: Integer;
  344. begin
  345.   Close;
  346.  
  347.   FPlayers.Free;
  348.  
  349.   if FProviders<>nil then
  350.   begin
  351.     for i:=0 to FProviders.Count-1 do
  352.       Dispose(PGUID(FProviders.Objects[i]));
  353.   end;
  354.   FProviders.Free;
  355.   FModemSetting.Free;
  356.   FTCPIPSetting.Free;
  357.   ClearSessionList;
  358.   FSessions.Free;
  359.   inherited Destroy;
  360. end;
  361.  
  362. type
  363.   TDXPlayRecvThread = class(TThread)
  364.   private
  365.     FDXPlay: TCustomDXPlay;
  366.     constructor Create(DXPlay: TCustomDXPlay);
  367.     destructor Destroy; override;
  368.     procedure Execute; override;
  369.   end;
  370.  
  371. constructor TDXPlayRecvThread.Create(DXPlay: TCustomDXPlay);
  372. begin
  373.   FDXPlay := DXPlay;
  374.  
  375.   FDXPlay.FRecvEvent[1] := CreateEvent(nil, False, False, nil);
  376.  
  377.   FreeOnTerminate := True;
  378.   inherited Create(True);
  379. end;
  380.  
  381. destructor TDXPlayRecvThread.Destroy;
  382. begin
  383.   FreeOnTerminate := False;
  384.   SetEvent(FDXPlay.FRecvEvent[1]);
  385.  
  386.   inherited Destroy;
  387.  
  388.   CloseHandle(FDXPlay.FRecvEvent[1]);
  389.  
  390.   FDXPlay.FRecvThread := nil;
  391.   FDXPlay.Close;
  392. end;
  393.  
  394. procedure TDXPlayRecvThread.Execute;
  395. begin
  396.   while WaitForMultipleObjects(2, @FDXPlay.FRecvEvent, False, INFINITE)=WAIT_OBJECT_0 do
  397.   begin
  398.     Synchronize(FDXPlay.ReceiveMessage);
  399.   end;
  400. end;
  401.  
  402. procedure TCustomDXPlay.ReceiveMessage;
  403. var
  404.   idFrom, idTo: DWORD;
  405.   hr: HRESULT;
  406.   lpvMsgBuffer: Pointer;
  407.   dwMsgBufferSize: DWORD;
  408.   Msg_CreatePlayerOrGroup: LPDPMSG_CREATEPLAYERORGROUP;
  409.   Msg_DeletePlayerOrGroup: LPDPMSG_CREATEPLAYERORGROUP;
  410.   Player: TDXPlayPlayer;
  411.   i: Integer;
  412. begin
  413.   FInThread := True;
  414.   try
  415.     try
  416.       lpvMsgBuffer := nil;
  417.       dwMsgBufferSize := 0;
  418.  
  419.       try
  420.         repeat
  421.           hr := FDPlay.Receive(idFrom, idTo, DPRECEIVE_ALL, lpvMsgBuffer^, dwMsgBufferSize);
  422.  
  423.           if hr=DPERR_BUFFERTOOSMALL then
  424.           begin
  425.             ReAllocMem(lpvMsgBuffer, dwMsgBufferSize);
  426.             hr := FDPlay.Receive(idFrom, idTo, DPRECEIVE_ALL, lpvMsgBuffer^, dwMsgBufferSize);
  427.           end;
  428.  
  429.           if (hr=0) and (dwMsgBufferSize>=SizeOf(DPMSG_GENERIC)) then
  430.           begin
  431.             if idFrom=DPID_SYSMSG then
  432.             begin
  433.               {  System message  }
  434.               case LPDPMSG_GENERIC(lpvMsgBuffer)^.dwType of
  435.                 DPSYS_CREATEPLAYERORGROUP:
  436.                     begin
  437.                       {  New player  }
  438.                       Msg_CreatePlayerOrGroup := lpvMsgBuffer;
  439.  
  440.                       if Msg_CreatePlayerOrGroup.dpId<>FLocalPlayer.FID then
  441.                       begin
  442.                         Player := TDXPlayPlayer.Create(Players);
  443.                         Player.FID := Msg_CreatePlayerOrGroup.dpId;
  444.                         Player.FRemotePlayer := True;
  445.  
  446.                         with Msg_CreatePlayerOrGroup.dpnName do
  447.                         begin
  448.                           if lpszShortNameA<>nil then
  449.                             Player.FName := lpszShortNameA;
  450.                         end;
  451.  
  452.                         DoAddPlayer(Player);
  453.                       end;
  454.                     end;
  455.                 DPSYS_DESTROYPLAYERORGROUP:
  456.                     begin
  457.                       {  Player deletion  }
  458.                       Msg_DeletePlayerOrGroup := lpvMsgBuffer;
  459.  
  460.                       if Msg_DeletePlayerOrGroup.dpId<>FLocalPlayer.FID then
  461.                       begin
  462.                         i := Players.IndexOf(Msg_DeletePlayerOrGroup.dpId);
  463.                         if i<>-1 then
  464.                         begin
  465.                           DoDeletePlayer(Players[i]);
  466.                           Players[i].Free;
  467.                         end;
  468.                       end;
  469.                     end;
  470.                 DPSYS_SESSIONLOST:
  471.                     begin
  472.                       {  The session was lost.  }
  473.                       DoSessionLost;
  474.                       Close;
  475.                     end;
  476.                 DPSYS_HOST:
  477.                     begin
  478.                       {  Here became a host.  }
  479.                       FIsHost := True;
  480.                     end;
  481.               end;
  482.             end else
  483.             begin
  484.               {  Application definition message  }
  485.               DoMessage(Players.Find(idFrom), lpvMsgBuffer, dwMsgBufferSize);
  486.             end;
  487.           end;
  488.         until hr<>0;
  489.       finally
  490.         FreeMem(lpvMsgBuffer);
  491.       end;
  492.     except
  493.       on E: Exception do
  494.         Application.HandleException(E);
  495.     end;
  496.   finally
  497.     FInThread := False;
  498.   end;
  499. end;
  500.  
  501. procedure TCustomDXPlay.DoAddPlayer(Player: TDXPlayPlayer);
  502. begin
  503.   if Assigned(FOnAddPlayer) then FOnAddPlayer(Self, Player)
  504. end;
  505.  
  506. procedure TCustomDXPlay.DoClose;
  507. begin
  508.   if Assigned(FOnClose) then FOnClose(Self);
  509. end;
  510.  
  511. procedure TCustomDXPlay.DoDeletePlayer(Player: TDXPlayPlayer);
  512. begin
  513.   if Assigned(FOnDeletePlayer) then FOnDeletePlayer(Self, Player)
  514. end;
  515.  
  516. procedure TCustomDXPlay.DoMessage(From: TDXPlayPlayer; Data: Pointer; DataSize: Integer);
  517. begin
  518.   if Assigned(FOnMessage) then FOnMessage(Self, From, Data, DataSize);
  519. end;
  520.  
  521. procedure TCustomDXPlay.DoOpen;
  522. begin
  523.   if Assigned(FOnOpen) then FOnOpen(Self);
  524. end;
  525.  
  526. procedure TCustomDXPlay.DoSessionLost;
  527. begin
  528.   if Assigned(FOnSessionLost) then FOnSessionLost(Self);
  529. end;
  530.  
  531. function TCustomDXPlay.GetProviders: TStrings;
  532.  
  533.   function EnumProviderCallback(const lpguidSP: TGUID; lpSPName: LPSTR;
  534.       dwMajorVersion: DWORD; dwMinorVersion: DWORD; lpContext: Pointer):
  535.       BOOL; stdcall;
  536.   var
  537.     GUID: PGUID;
  538.   begin
  539.     GUID := New(PGUID);
  540.     Move(lpguidSP, GUID^, SizeOf(TGUID));
  541.     TStrings(lpContext).AddObject(lpSPName, TObject(GUID));
  542.     Result := True;
  543.   end;
  544.  
  545. begin
  546.   if FProviders=nil then
  547.   begin
  548.     FProviders := TStringList.Create;
  549.     try
  550.       DXDirectPlayEnumerateA(@EnumProviderCallback, FProviders);
  551.     except
  552.       FProviders.Free; FProviders := nil;
  553.       raise;
  554.     end;
  555.   end;
  556.  
  557.   Result := FProviders;
  558. end;
  559.  
  560. procedure TCustomDXPlay.GetSessions;
  561.  
  562.   function EnumSessionsCallback(const lpThisSD: DPSESSIONDESC2;
  563.       var lpdwTimeOut: DWORD; dwFlags: DWORD; lpContext: Pointer): BOOL; stdcall;
  564.   var
  565.     Guid: PGUID;
  566.   begin
  567.     if dwFlags and DPESC_TIMEDOUT<>0 then
  568.     begin
  569.       Result := False;
  570.       Exit;
  571.     end;
  572.  
  573.     Guid := New(PGUID);
  574.     Move(lpThisSD.guidInstance, Guid^, SizeOf(TGUID));
  575.     TStrings(lpContext).AddObject(lpThisSD.lpszSessionNameA, TObject(Guid));
  576.  
  577.     Result := True;
  578.   end;
  579.  
  580. var
  581.   dpDesc: DPSESSIONDESC2;
  582.   hr: HRESULT;
  583. begin
  584.   if FDPlay=nil then
  585.     raise EDXPlayError.Create(SDXPlayNotConnectedNow);
  586.  
  587.   ClearSessionList;
  588.  
  589.   FillChar(dpDesc, SizeOf(dpDesc), 0);
  590.   dpDesc.dwSize := SizeOf(dpDesc);
  591.   dpDesc.guidApplication := DXPlayStringToGUID(FGUID);
  592.  
  593.   hr := FDPlay.EnumSessions(dpDesc, 0, @EnumSessionsCallback, FSessions, DPENUMSESSIONS_AVAILABLE);
  594.   if hr=DPERR_USERCANCEL then Abort;
  595.   if hr<>0 then
  596.     raise EDXPlayError.Create(SDXPlaySessionListCannotBeAcquired);
  597.  
  598.   FReadSessioned := True;
  599. end;
  600.  
  601. function TCustomDXPlay.GetSessionsPty: TStrings;
  602. begin
  603.   if not FReadSessioned then GetSessions;
  604.   Result := FSessions;       
  605. end;
  606.  
  607. function TCustomDXPlay.GetProviderNameFromGUID(const ProviderGUID: TGUID): string;
  608. var
  609.   i: Integer;
  610. begin
  611.   for i:=0 to Providers.Count-1 do
  612.     if CompareMem(PGUID(Providers.Objects[i]), @ProviderGUID, SizeOf(TGUID)) then
  613.     begin
  614.       Result := Providers[i];
  615.       Exit;
  616.     end;
  617.  
  618.   raise EDXPlayError.Create(SDXPlayProviderSpecifiedGUIDNotFound);
  619. end;
  620.  
  621. procedure TCustomDXPlay.CreateDPlayWithoutDialog(out DPlay: IDirectPlay3A; const ProviderName: string);
  622. var
  623.   i: Integer;
  624.   ProviderGUID: TGUID;
  625.   addressElements: array[0..15] of DPCOMPOUNDADDRESSELEMENT;
  626.   dwElementCount: Integer;
  627.   Lobby1: IDirectPlayLobbyA;
  628.   Lobby: IDirectPlayLobby2A;
  629.   lpAddress: Pointer;
  630.   dwAddressSize: DWORD;
  631. begin
  632.   i := Providers.IndexOf(ProviderName);
  633.   if i=-1 then
  634.     raise EDXPlayError.CreateFmt(SDXPlayProviderNotFound, [ProviderName]);
  635.   ProviderGUID := PGUID(Providers.Objects[i])^;
  636.  
  637.   {  DirectPlay address making  }
  638.   if DXDirectPlayLobbyCreateA(PGUID(nil)^, Lobby1, nil, nil, 0)<>0 then
  639.     raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  640.   Lobby := Lobby1 as IDirectPlayLobby2A;
  641.  
  642.   FillChar(addressElements, SizeOf(addressElements), 0);
  643.   dwElementCount := 0;
  644.  
  645.   addressElements[dwElementCount].guidDataType := DPAID_ServiceProvider;
  646.   addressElements[dwElementCount].dwDataSize := SizeOf(TGUID);
  647.   addressElements[dwElementCount].lpData := @ProviderGUID;
  648.   Inc(dwElementCount);
  649.  
  650.   if CompareMem(@ProviderGUID, @DPSPGUID_MODEM, SizeOf(TGUID)) and ModemSetting.Enabled then
  651.   begin
  652.     {  Modem  }
  653.     if ModemSetting.FModemName<>'' then
  654.     begin
  655.       addressElements[dwElementCount].guidDataType := DPAID_Modem;
  656.       addressElements[dwElementCount].dwDataSize := Length(ModemSetting.FModemName)+1;
  657.       addressElements[dwElementCount].lpData := PChar(ModemSetting.FModemName);
  658.       Inc(dwElementCount);
  659.     end;
  660.  
  661.     if ModemSetting.FPhoneNumber<>'' then
  662.     begin
  663.       addressElements[dwElementCount].guidDataType := DPAID_Phone;
  664.       addressElements[dwElementCount].dwDataSize := Length(ModemSetting.FPhoneNumber)+1;
  665.       addressElements[dwElementCount].lpData := PChar(ModemSetting.FPhoneNumber);
  666.       Inc(dwElementCount);
  667.     end;
  668.   end else
  669.   if CompareMem(@ProviderGUID, @DPSPGUID_TCPIP, SizeOf(TGUID)) and TCPIPSetting.Enabled then
  670.   begin
  671.     {  TCP/IP  }
  672.     if TCPIPSetting.FHostName<>'' then
  673.     begin
  674.       addressElements[dwElementCount].guidDataType := DPAID_INet;
  675.       addressElements[dwElementCount].dwDataSize := Length(TCPIPSetting.FHostName)+1;
  676.       addressElements[dwElementCount].lpData := PChar(TCPIPSetting.FHostName);
  677.       Inc(dwElementCount);
  678.     end;
  679.   end;
  680.  
  681.   if Lobby.CreateCompoundAddress(addressElements[0], dwElementCount, nil^, dwAddressSize)<>DPERR_BUFFERTOOSMALL then
  682.     raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  683.  
  684.   GetMem(lpAddress, dwAddressSize);
  685.   try
  686.     FillChar(lpAddress^, dwAddressSize, 0);
  687.  
  688.     if Lobby.CreateCompoundAddress(addressElements[0], dwElementCount, lpAddress^, dwAddressSize)<>0 then
  689.       raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  690.  
  691.     {  DirectPlay initialization  }
  692.     if CoCreateInstance(CLSID_DirectPlay, nil, CLSCTX_INPROC_SERVER, IID_IDirectPlay3A, DPlay)<>0 then
  693.       raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  694.     try
  695.       {  DirectPlay address initialization  }
  696.       if DPlay.InitializeConnection(lpAddress, 0)<>0 then
  697.         raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]);
  698.     except
  699.       DPlay := nil;
  700.       raise;
  701.     end;
  702.   finally
  703.     FreeMem(lpAddress);
  704.   end;
  705. end;
  706.  
  707. procedure TCustomDXPlay.ClearSessionList;
  708. var
  709.   i: Integer;
  710. begin
  711.   FReadSessioned := False;
  712.   for i:=0 to FSessions.Count-1 do
  713.     Dispose(PGUID(FSessions.Objects[i]));
  714.   FSessions.Clear;
  715. end;
  716.  
  717. procedure TCustomDXPlay.Open;
  718. var
  719.   PlayerName: string;
  720. begin
  721.   Close;
  722.   try
  723.     if not OpenDPlayWithLobby(PlayerName) then
  724.     begin
  725.       if not OpenDPlayWithoutLobby(PlayerName) then
  726.         Abort;
  727.     end;
  728.  
  729.     Open_(PlayerName);
  730.   except
  731.     Close;
  732.     raise;
  733.   end;
  734. end;
  735.  
  736. procedure TCustomDXPlay.Open2(const NewSession: Boolean; const SessionName, PlayerName: string);
  737. begin
  738.   if not OpenDPlayWithoutLobby2(NewSession, ProviderName, SessionName, PlayerName) then
  739.     Abort;
  740.  
  741.   Open_(PlayerName);
  742. end;
  743.  
  744. procedure TCustomDXPlay.Open_(NameS: string);
  745.  
  746.   function EnumPlayersCallback2(dpId: DPID; dwPlayerType: DWORD;
  747.     const lpName: DPNAME; dwFlags: DWORD; lpContext: Pointer): BOOL;
  748.     stdcall;
  749.   var
  750.     Player: TDXPlayPlayer;
  751.   begin
  752.     Player := TDXPlayPlayer.Create(TCustomDXPlay(lpContext).Players);
  753.     Player.FID := dpId;
  754.     Player.FRemotePlayer := True;
  755.  
  756.     with lpName do
  757.     begin
  758.       if lpszShortNameA<>nil then
  759.         Player.FName := lpszShortNameA;
  760.     end;
  761.  
  762.     Result := True;
  763.   end;
  764.  
  765. var
  766.   Name2: array[0..1023] of Char;
  767.   Name: DPNAME;
  768. begin
  769.   if FOpened then Close;
  770.   FOpened := True;
  771.   try
  772.     {  Player making  }
  773.     StrLCopy(@Name2, PChar(NameS), SizeOf(Name2));
  774.  
  775.     Name.lpszShortNameA := @Name2;
  776.     Name.lpszLongNameA := nil;
  777.  
  778.     FRecvEvent[0] := CreateEvent(nil, False, False, nil);
  779.  
  780.     FLocalPlayer := TDXPlayPlayer.Create(FPlayers);
  781.     FLocalPlayer.FName := NameS;
  782.  
  783.     if FDPlay.CreatePlayer(FLocalPlayer.FID, Name, FRecvEvent[0], nil^, 0, 0)<>DP_OK then
  784.       raise EDXPlayError.CreateFmt(SCannotOpened, [FSessionName]);
  785.  
  786.     {  Player enumeration  }
  787.     FDPlay.EnumPlayers(PGUID(nil)^, @EnumPlayersCallback2, Self, DPENUMPLAYERS_REMOTE);
  788.  
  789.     FIsHost := FPlayers.Count=1;
  790.  
  791.     FCalledDoOpen := True; DoOpen;
  792.     DoAddPlayer(FLocalPlayer);
  793.  
  794.     {  Thread start  }
  795.     FRecvThread := TDXPlayRecvThread.Create(Self);
  796.     FRecvThread.Resume;
  797.   except
  798.     Close;
  799.     raise;
  800.   end;
  801. end;
  802.  
  803. function TCustomDXPlay.OpenDPlayWithLobby(out Name: string): Boolean;
  804. var
  805.   DPlay1: IDirectPlay2;
  806.   Lobby: IDirectPlayLobbyA;
  807.   dwSize: DWORD;
  808.   ConnectionSettings: ^DPLCONNECTION;
  809. begin
  810.   Result := False;
  811.  
  812.   if DXDirectPlayLobbyCreateA(PGUID(nil)^, Lobby, nil, nil, 0)<>0 then
  813.     Exit;
  814.  
  815.   if Lobby.GetConnectionSettings(0, DPLCONNECTION(nil^), dwSize)<>DPERR_BUFFERTOOSMALL then
  816.     Exit;
  817.  
  818.   GetMem(ConnectionSettings, dwSize);
  819.   try
  820.     if Lobby.GetConnectionSettings(0, ConnectionSettings^, dwSize)<>0 then
  821.       Exit;
  822.  
  823.     with ConnectionSettings^.lpSessionDesc^ do
  824.     begin
  825.       dwFlags := DPSESSION_MIGRATEHOST or DPSESSION_KEEPALIVE;
  826.       dwMaxPlayers := FMaxPlayers;
  827.     end;
  828.  
  829.     if Lobby.SetConnectionSettings(0, 0, ConnectionSettings^)<>0 then
  830.       Exit;
  831.  
  832.     if Lobby.Connect(0, DPlay1, nil)<>0 then
  833.       Exit;
  834.     FDPlay := DPlay1 as IDirectPlay3A;
  835.  
  836.     with ConnectionSettings.lpSessionDesc^ do
  837.     begin
  838.       if lpszSessionNameA<>nil then
  839.         FSessionName := lpszSessionNameA;
  840.     end;
  841.  
  842.     with ConnectionSettings.lpPlayerName^ do
  843.     begin
  844.       if lpszShortNameA<>nil then
  845.         Name := lpszShortNameA;
  846.     end;
  847.   finally
  848.     FreeMem(ConnectionSettings);
  849.   end;
  850.  
  851.   Result := True;
  852. end;
  853.  
  854. function TCustomDXPlay.OpenDPlayWithoutLobby(out Name: string): Boolean;
  855. var
  856.   Form: TDelphiXDXPlayForm;
  857. begin
  858.   Form := TDelphiXDXPlayForm.Create(Application);
  859.   try
  860.     Form.DXPlay := Self;
  861.     Form.ShowModal;
  862.  
  863.     Result := Form.Tag<>0;
  864.  
  865.     FDPlay := Form.DPlay;
  866.     Name := Form.PlayerName;
  867.     FProviderName := Form.ProviderName;
  868.     FSessionName := Form.SessionName;
  869.   finally
  870.     Form.Free;
  871.   end;
  872. end;
  873.  
  874. function TCustomDXPlay.OpenDPlayWithoutLobby2(const NewSession: Boolean;
  875.   const ProviderName, SessionName, PlayerName: string): Boolean;
  876. var
  877.   dpDesc: DPSESSIONDESC2;
  878.   i: Integer;
  879.   hr: HRESULT;
  880. begin
  881.   Result := False;
  882.  
  883.   if FDPlay=nil then
  884.     raise EDXPlayError.Create(SDXPlayNotConnectedNow);
  885.  
  886.   if SessionName='' then
  887.     raise EDXPlayError.Create(SDXPlaySessionNameIsNotSpecified);
  888.  
  889.   if PlayerName='' then
  890.     raise EDXPlayError.Create(SDXPlayPlayerNameIsNotSpecified);
  891.  
  892.   if NewSession then
  893.   begin
  894.     {  Session connection  }
  895.     FillChar(dpDesc, SizeOf(dpDesc), 0);
  896.     dpDesc.dwSize := SizeOf(dpDesc);
  897.     dpDesc.dwFlags := DPSESSION_MIGRATEHOST or DPSESSION_KEEPALIVE;
  898.     dpDesc.lpszSessionNameA := PChar(SessionName);
  899.     dpDesc.guidApplication := DXPlayStringToGUID(GUID);
  900.     dpDesc.dwMaxPlayers := MaxPlayers;
  901.  
  902.     hr := FDPlay.Open(dpDesc, DPOPEN_CREATE);
  903.     if hr=DPERR_USERCANCEL then Exit;
  904.     if hr<>0 then
  905.       raise EDXPlayError.CreateFmt(SDXPlaySessionCannotOpened, [FSessionName]);
  906.   end else
  907.   begin
  908.     {  Session connection  }
  909.     {  Enum session  }
  910.     i := Sessions.IndexOf(SessionName);
  911.     if i=-1 then raise EDXPlayError.CreateFmt(SDXPlaySessionNotFound, [SessionName]);
  912.  
  913.     FillChar(dpDesc, SizeOf(dpDesc), 0);
  914.     dpDesc.dwSize := SizeOf(dpDesc);
  915.     dpDesc.guidInstance := PGUID(Sessions.Objects[i])^;
  916.     dpDesc.guidApplication := DXPlayStringToGUID(GUID);
  917.  
  918.     hr := FDPlay.Open(dpDesc, DPOPEN_JOIN);
  919.     if hr=DPERR_USERCANCEL then Exit;
  920.     if hr<>0 then
  921.       raise EDXPlayError.CreateFmt(SDXPlaySessionCannotOpened, [FSessionName]);
  922.   end;
  923.  
  924.   Result := True;
  925.  
  926.   FSessionName := SessionName;
  927. end;
  928.  
  929. procedure TCustomDXPlay.Close;
  930. begin
  931.   FOpened := False;
  932.   FReadSessioned := False;
  933.  
  934.   try
  935.     if FCalledDoOpen then
  936.     begin
  937.       FCalledDoOpen := False;
  938.       DoClose;
  939.     end;
  940.   finally
  941.     if FDPlay<>nil then
  942.     begin
  943.       if FLocalPlayer<>nil then FDPlay.DestroyPlayer(FLocalPlayer.FID);
  944.       FDPlay.Close;
  945.     end;
  946.  
  947.     FProviderName := '';
  948.     FSessionName := '';
  949.     ClearSessionList;
  950.  
  951.     FDPlay := nil;
  952.  
  953.     if FInThread then
  954.       SetEvent(FRecvEvent[1])
  955.     else
  956.       FRecvThread.Free;
  957.     CloseHandle(FRecvEvent[0]);
  958.  
  959.     FPlayers.Clear;
  960.  
  961.     FLocalPlayer := nil;
  962.   end;
  963. end;
  964.  
  965. procedure TCustomDXPlay.SendMessage(ToID: DPID; Data: Pointer; DataSize: Integer);
  966. begin
  967.   SendMessageEx(ToID, Data, DataSize, DPSEND_GUARANTEED);
  968. end;
  969.  
  970. procedure TCustomDXPlay.SendMessageEx(ToID: DPID; Data: Pointer; DataSize: Integer; dwFlags: DWORD);
  971. begin
  972.   if not Opened then Exit;
  973.  
  974.   if DataSize<SizeOf(DPMSG_GENERIC) then
  975.     raise EDXPlayError.Create(SDXPlayMessageIllegal);
  976.  
  977.   if ToID=FLocalPlayer.ID then
  978.   begin
  979.     {  Message to me  }
  980.     DoMessage(FLocalPlayer, Data, DataSize);
  981.   end else
  982.     FDPlay.Send(FLocalPlayer.ID, ToID, dwFlags, Data^, DataSize)
  983. end;
  984.  
  985. procedure TCustomDXPlay.SetGUID(const Value: string);
  986. begin
  987.   if Value<>FGUID then
  988.   begin
  989.     if Value='' then
  990.     begin
  991.       FGUID := GUIDToString(GUID_NULL);
  992.     end else
  993.     begin
  994.       FGUID := GUIDToString(DXPlayStringToGUID(Value));
  995.     end;
  996.   end;
  997. end;
  998.  
  999. procedure TCustomDXPlay.SetProviderName(const Value: string);
  1000. begin
  1001.   Close;
  1002.   FProviderName := Value;
  1003.   if FProviderName='' then Exit;
  1004.   try
  1005.     CreateDPlayWithoutDialog(FDPlay, Value);
  1006.   except
  1007.     FProviderName := '';
  1008.     raise;
  1009.   end;
  1010. end;
  1011.  
  1012. initialization
  1013.   CoInitialize(nil);
  1014. finalization
  1015.   CoUninitialize;
  1016. end.
  1017.