Rev 4 | Rev 16 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | unit DXPlay; |
2 | |||
3 | interface |
||
4 | |||
5 | {$INCLUDE DelphiXcfg.inc} |
||
6 | |||
10 | daniel-mar | 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 | |||
1 | daniel-mar | 11 | uses |
4 | daniel-mar | 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 | |||
1 | daniel-mar | 25 | type |
4 | daniel-mar | 26 | {$IfDef DX9} |
27 | TDPID = DWORD; |
||
28 | {$EndIf} |
||
1 | daniel-mar | 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 |
||
4 | daniel-mar | 109 | FDPlay: //{$IfDef DX7} |
110 | IDirectPlay4A;//{$Else}IDirectPlay8Address{$EndIf}; |
||
1 | daniel-mar | 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; |
||
4 | daniel-mar | 138 | procedure CreateDPlayWithoutDialog(out DPlay: |
139 | //{$IfDef DX7} |
||
140 | IDirectPlay4A; |
||
141 | //{$Else}IDirectPlay8Address{$EndIf}; |
||
142 | const ProviderName: string); |
||
1 | daniel-mar | 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; |
||
4 | daniel-mar | 217 | function DXDirectPlayCreate(const lpGUID: TGUID; out lplpDP: |
218 | //{$IfDef DX7} |
||
219 | IDirectPlay; |
||
220 | //{$Else}IDirectPlay8Server{$EndIf}; |
||
1 | daniel-mar | 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 | |||
4 | daniel-mar | 253 | function DXDirectPlayCreate(const lpGUID: TGUID; out lplpDP: |
254 | //{$IfDef DX7} |
||
255 | IDirectPlay; |
||
256 | //{$Else}IDirectPlay8Server{$EndIf}; |
||
1 | daniel-mar | 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; |
||
4 | daniel-mar | 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; |
||
1 | daniel-mar | 272 | |
4 | daniel-mar | 273 | function DXDirectPlayLobbyCreate(const lpguidSP: TGUID; out lplpDPL: IDirectPlayLobbyW; |
274 | lpUnk: IUnknown; lpData: Pointer; dwDataSize: DWORD): HRESULT; |
||
1 | daniel-mar | 275 | type |
4 | daniel-mar | 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 |
||
1 | daniel-mar | 285 | TDirectPlayEnumerateA= function(lpEnumDPCallback: TDPEnumDPCallbackA; lpContext: Pointer): HRESULT; stdcall; |
286 | begin |
||
287 | Result := TDirectPlayEnumerateA(DXLoadLibrary('DPlayX.dll', 'DirectPlayEnumerateA')) |
||
288 | (lpEnumDPCallback, lpContext); |
||
289 | end; |
||
290 | |||
4 | daniel-mar | 291 | function DXDirectPlayLobbyCreate(const lpguidSP: TGUID; out lplpDPL: IDirectPlayLobbyA; |
1 | daniel-mar | 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; |
||
4 | daniel-mar | 300 | {$ENDIF} |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 366 | {$IFDEF UNICODE} |
367 | Lobby1: IDirectPlayLobbyW; |
||
368 | Lobby: IDirectPlayLobby2W; |
||
369 | DPlay: IDirectPlay4W; |
||
370 | {$ELSE} |
||
1 | daniel-mar | 371 | Lobby1: IDirectPlayLobbyA; |
372 | Lobby: IDirectPlayLobby2A; |
||
4 | daniel-mar | 373 | DPlay: IDirectPlay4A; |
374 | {$ENDIF} |
||
1 | daniel-mar | 375 | DPlay1: IDirectPlay; |
376 | lpAddress: Pointer; |
||
377 | dwAddressSize: DWORD; |
||
378 | begin |
||
379 | if FModemNames=nil then |
||
380 | begin |
||
381 | FModemNames := TStringList.Create; |
||
382 | try |
||
4 | daniel-mar | 383 | if DXDirectPlayLobbyCreate(PGUID(nil)^, Lobby1, nil, nil, 0)<>0 then |
1 | daniel-mar | 384 | raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]); |
4 | daniel-mar | 385 | Lobby := Lobby1 as {$IFDEF UNICODE}IDirectPlayLobby2W{$ELSE}IDirectPlayLobby2A{$ENDIF}; |
1 | daniel-mar | 386 | |
387 | if DXDirectPlayCreate(DPSPGUID_MODEM, DPlay1, nil)<>0 then |
||
388 | raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]); |
||
4 | daniel-mar | 389 | DPlay := DPlay1 as {$IFDEF UNICODE}IDirectPlay4W{$ELSE}IDirectPlay4A{$ENDIF}; |
1 | daniel-mar | 390 | |
391 | { get size of player address for all players } |
||
4 | daniel-mar | 392 | if DPlay.GetPlayerAddress(DPID_ALLPLAYERS, nil, dwAddressSize)<>DPERR_BUFFERTOOSMALL then |
1 | daniel-mar | 393 | raise EDXPlayError.Create(SDXPlayModemListCannotBeAcquired); |
394 | |||
395 | GetMem(lpAddress, dwAddressSize); |
||
396 | try |
||
397 | FillChar(lpAddress^, dwAddressSize, 0); |
||
398 | |||
399 | { get the address } |
||
4 | daniel-mar | 400 | if DPlay.GetPlayerAddress(DPID_ALLPLAYERS, lpAddress, dwAddressSize)<>0 then |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 526 | hr := FDPlay.Receive(idFrom, idTo, DPRECEIVE_ALL, lpvMsgBuffer, dwMsgBufferSize); |
1 | daniel-mar | 527 | |
528 | if hr=DPERR_BUFFERTOOSMALL then |
||
529 | begin |
||
530 | ReAllocMem(lpvMsgBuffer, dwMsgBufferSize); |
||
4 | daniel-mar | 531 | hr := FDPlay.Receive(idFrom, idTo, DPRECEIVE_ALL, lpvMsgBuffer, dwMsgBufferSize); |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 553 | {$IFDEF UNICODE} |
554 | if lpszShortNameW<>nil then |
||
555 | Player.FName := lpszShortNameW; |
||
556 | {$ELSE} |
||
1 | daniel-mar | 557 | if lpszShortNameA<>nil then |
558 | Player.FName := lpszShortNameA; |
||
4 | daniel-mar | 559 | {$ENDIF} |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 574 | begin |
1 | daniel-mar | 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 | |||
4 | daniel-mar | 665 | function EnumProviderCallback(const lpguidSP: TGUID; lpSPName: {$IFDEF UNICODE}LPCTSTR{$ELSE}LPSTR{$ENDIF}; |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 682 | DXDirectPlayEnumerate(@EnumProviderCallback, FProviders); |
1 | daniel-mar | 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)); |
||
4 | daniel-mar | 707 | {$IFDEF UNICODE} |
708 | TStrings(lpContext).AddObject(lpThisSD.lpszSessionNameW, TObject(Guid)); |
||
709 | {$ELSE} |
||
1 | daniel-mar | 710 | TStrings(lpContext).AddObject(lpThisSD.lpszSessionNameA, TObject(Guid)); |
4 | daniel-mar | 711 | {$ENDIF} |
1 | daniel-mar | 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; |
||
4 | daniel-mar | 762 | {$IFDEF UNICODE} |
763 | Lobby1: IDirectPlayLobbyW; |
||
764 | Lobby: IDirectPlayLobby2W; |
||
765 | {$ELSE} |
||
1 | daniel-mar | 766 | Lobby1: IDirectPlayLobbyA; |
767 | Lobby: IDirectPlayLobby2A; |
||
4 | daniel-mar | 768 | {$ENDIF} |
1 | daniel-mar | 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 } |
||
4 | daniel-mar | 778 | if DXDirectPlayLobbyCreate(PGUID(nil)^, Lobby1, nil, nil, 0)<>0 then |
1 | daniel-mar | 779 | raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]); |
4 | daniel-mar | 780 | Lobby := Lobby1 as {$IFDEF UNICODE}IDirectPlayLobby2W{$ELSE}IDirectPlayLobby2A{$ENDIF}; |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 821 | begin |
1 | daniel-mar | 822 | addressElements[dwElementCount].guidDataType := DPAID_INetPort; |
823 | addressElements[dwElementCount].dwDataSize := SizeOf(TCPIPSetting.FPort); |
||
824 | addressElements[dwElementCount].lpData := @TCPIPSetting.FPort; |
||
4 | daniel-mar | 825 | Inc(dwElementCount); |
1 | daniel-mar | 826 | end; |
827 | end; |
||
828 | |||
4 | daniel-mar | 829 | if Lobby.CreateCompoundAddress(addressElements[0], dwElementCount, nil, dwAddressSize)<>DPERR_BUFFERTOOSMALL then |
1 | daniel-mar | 830 | raise EDXPlayError.CreateFmt(SCannotInitialized, [SDirectPlay]); |
831 | |||
832 | GetMem(lpAddress, dwAddressSize); |
||
833 | try |
||
834 | FillChar(lpAddress^, dwAddressSize, 0); |
||
835 | |||
4 | daniel-mar | 836 | if Lobby.CreateCompoundAddress(addressElements[0], dwElementCount, lpAddress, dwAddressSize)<>0 then |
1 | daniel-mar | 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; |
||
4 | daniel-mar | 897 | var |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 906 | {$IFDEF UNICODE} |
907 | if lpszShortNameW<>nil then |
||
908 | Player.FName := lpszShortNameW; |
||
909 | {$ELSE} |
||
1 | daniel-mar | 910 | if lpszShortNameA<>nil then |
911 | Player.FName := lpszShortNameA; |
||
4 | daniel-mar | 912 | {$ENDIF} |
1 | daniel-mar | 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 | |||
4 | daniel-mar | 936 | if FDPlay.CreatePlayer(FLocalPlayer.FID, @Name, FRecvEvent[0], nil, 0, 0)<>DP_OK then |
1 | daniel-mar | 937 | raise EDXPlayError.CreateFmt(SCannotOpened, [FSessionName]); |
938 | |||
939 | { Player enumeration } |
||
4 | daniel-mar | 940 | FDPlay.EnumPlayers(PGUID(nil), @EnumPlayersCallback2, Self, DPENUMPLAYERS_REMOTE); |
1 | daniel-mar | 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.Resume; |
||
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; |
||
4 | daniel-mar | 974 | {$IFDEF UNICODE} |
975 | Lobby: IDirectPlayLobbyW; |
||
976 | {$ELSE} |
||
1 | daniel-mar | 977 | Lobby: IDirectPlayLobbyA; |
4 | daniel-mar | 978 | {$ENDIF} |
1 | daniel-mar | 979 | dwSize: DWORD; |
980 | ConnectionSettings: PDPLConnection; |
||
981 | begin |
||
982 | Result := False; |
||
983 | |||
4 | daniel-mar | 984 | if DXDirectPlayLobbyCreate(PGUID(nil)^, Lobby, nil, nil, 0)<>0 then |
1 | daniel-mar | 985 | Exit; |
986 | |||
4 | daniel-mar | 987 | if Lobby.GetConnectionSettings(0, PDPLConnection(nil), dwSize)<>DPERR_BUFFERTOOSMALL then |
1 | daniel-mar | 988 | Exit; |
989 | |||
990 | GetMem(ConnectionSettings, dwSize); |
||
991 | try |
||
4 | daniel-mar | 992 | if Lobby.GetConnectionSettings(0, ConnectionSettings, dwSize)<>0 then |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 1011 | {$IFDEF UNICODE} |
1012 | if lpszSessionNameW<>nil then |
||
1013 | FSessionName := lpszSessionNameW; |
||
1014 | {$ELSE} |
||
1 | daniel-mar | 1015 | if lpszSessionNameA<>nil then |
1016 | FSessionName := lpszSessionNameA; |
||
4 | daniel-mar | 1017 | {$ENDIF} |
1 | daniel-mar | 1018 | end; |
1019 | |||
1020 | with ConnectionSettings.lpPlayerName^ do |
||
1021 | begin |
||
4 | daniel-mar | 1022 | {$IFDEF UNICODE} |
1023 | if lpszShortNameW<>nil then |
||
1024 | Name := lpszShortNameW; |
||
1025 | {$ELSE} |
||
1 | daniel-mar | 1026 | if lpszShortNameA<>nil then |
1027 | Name := lpszShortNameA; |
||
4 | daniel-mar | 1028 | {$ENDIF} |
1 | daniel-mar | 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; |
||
4 | daniel-mar | 1083 | {$IFDEF UNICODE} |
1084 | dpDesc.lpszSessionNameW := {$IFDEF VER12UP}PChar{$ELSE}PWideChar{$ENDIF}(SessionName); |
||
1085 | {$ELSE} |
||
1086 | dpDesc.lpszSessionNameA := PAnsiChar(SessionName); |
||
1087 | {$ENDIF} |
||
1 | daniel-mar | 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; |
||
4 | daniel-mar | 1139 | |
1 | daniel-mar | 1140 | ClearSessionList; |
1141 | |||
1142 | FDPlay := nil; |
||
1143 | ChangeDPlay; |
||
1144 | |||
1145 | if FInThread then |
||
1146 | SetEvent(FRecvEvent[1]) |
||
1147 | else |
||
1148 | FRecvThread.Free; |
||
4 | daniel-mar | 1149 | |
1 | daniel-mar | 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 |
||
4 | daniel-mar | 1171 | FDPlay.SendEx(FLocalPlayer.ID, ToID, DPSEND_GUARANTEED or DPSEND_ASYNC, Data, DataSize, 0, 0, nil, nil) |
1 | daniel-mar | 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 | { 自分宛のメッセ[ジ } |
||
1188 | DoMessage(FLocalPlayer, Data, DataSize); |
||
1189 | end else |
||
4 | daniel-mar | 1190 | FDPlay.SendEx(FLocalPlayer.ID, ToID, dwFlags, Data, DataSize, |
1 | daniel-mar | 1191 | 0, 0, nil, @Result); // 0 以外はサポ[トしないデバイスあるので使わない |
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; |
||
4 | daniel-mar | 1235 | end. |