Commit 4da59ea6 authored by Peter Hunnisett's avatar Peter Hunnisett Committed by Alexandre Julliard

- Make ref counting a little more efficient

- Correct suspended process resumption - Don't use sys/queue.h anymore - Properly initialize the global semaphore across processes - Create a mapped file for shared data structures - Change some trace messages - Allocate dynamic shared data from the mapped file - Rework setting and retrieving lobby settings from shared memory - Add infrastructure for syncronization after app launch - Small documentation update - Include some stuff missing from header - Start on dp and dpl message infrastructure - Unicode versions of player/group commands added - Combined Connect/ConnectEx and Open/SecureOpen - More implementation
parent 961053fd
......@@ -6,12 +6,14 @@ MODULE = dplayx
SOVERSION = 1.0
IMPORTS = ole32
C_SRCS = dplay.c \
dplobby.c \
dpclassfactory.c \
dplayx_main.c \
dplayx_global.c \
name_server.c
C_SRCS = \
dpclassfactory.c \
dplay.c \
dplayx_global.c \
dplayx_main.c \
dplayx_messages.c \
dplobby.c \
name_server.c
@MAKE_DLL_RULES@
......
......@@ -4,18 +4,31 @@
#include "dplay.h"
void DPLAYX_ConstructData(void);
void DPLAYX_DestructData(void);
HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID, LPVOID lpData, LPDWORD lpdwDataSize );
HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID, LPVOID lpData, LPDWORD lpdwDataSize );
HRESULT DPLAYX_SetConnectionSettingsA ( DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn );
HRESULT DPLAYX_SetConnectionSettingsW ( DWORD dwFlags, DWORD dwAppID, LPDPLCONNECTION lpConn );
BOOL DPLAYX_ConstructData(void);
BOOL DPLAYX_DestructData(void);
HRESULT DPLAYX_GetConnectionSettingsA ( DWORD dwAppID,
LPVOID lpData,
LPDWORD lpdwDataSize,
LPBOOL lpbSendHaveReadMessage );
HRESULT DPLAYX_GetConnectionSettingsW ( DWORD dwAppID,
LPVOID lpData,
LPDWORD lpdwDataSize,
LPBOOL lpbSendHaveReadMessage );
HRESULT DPLAYX_SetConnectionSettingsA ( DWORD dwFlags,
DWORD dwAppID,
LPDPLCONNECTION lpConn );
HRESULT DPLAYX_SetConnectionSettingsW ( DWORD dwFlags,
DWORD dwAppID,
LPDPLCONNECTION lpConn );
BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent );
BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID );
BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait );
BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void);
LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index );
BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd );
void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd );
......
/*
* DPLAYX.DLL LibMain
*
* Copyright 1999 - Peter Hunnisett
* Copyright 1999,2000 - Peter Hunnisett
*
* contact <hunnise@nortelnetworks.com>
*/
......@@ -17,34 +17,29 @@ static DWORD DPLAYX_dwProcessesAttached = 0;
BOOL WINAPI DPLAYX_LibMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
TRACE( "(%p,0x%08lx,%p) & 0x%08lx\n", hinstDLL, fdwReason, lpvReserved, DPLAYX_dwProcessesAttached );
TRACE( "(%u,0x%08lx,%p) & 0x%08lx\n", hinstDLL, fdwReason, lpvReserved, DPLAYX_dwProcessesAttached );
switch ( fdwReason )
{
case DLL_PROCESS_ATTACH:
{
if ( DPLAYX_dwProcessesAttached == 0 )
if ( DPLAYX_dwProcessesAttached++ == 0 )
{
/* First instance perform construction of global processor data */
TRACE( "DPLAYX_dwProcessesAttached = 0x%08lx\n", DPLAYX_dwProcessesAttached );
DPLAYX_ConstructData();
return DPLAYX_ConstructData();
}
DPLAYX_dwProcessesAttached++;
break;
}
case DLL_PROCESS_DETACH:
{
DPLAYX_dwProcessesAttached--;
if ( DPLAYX_dwProcessesAttached == 0 )
if ( --DPLAYX_dwProcessesAttached == 0 )
{
/* Last instance perform destruction of global processor data */
DPLAYX_DestructData();
/* Last instance performs destruction of global processor data */
return DPLAYX_DestructData();
}
break;
......
/* DirectPlay & DirectPlayLobby messaging implementation
*
* Copyright 2000 - Peter Hunnisett
*
* <presently under construction - contact hunnise@nortelnetworks.com>
*
*/
#include "winbase.h"
#include "debugtools.h"
#include "dplayx_messages.h"
DEFAULT_DEBUG_CHANNEL(dplay)
static DWORD CALLBACK DPLAYX_MSG_ThreadMain( LPVOID lpContext );
/* Create the message reception thread to allow the application to receive
* asynchronous message reception
*/
DWORD CreateMessageReceptionThread( HANDLE hNotifyEvent )
{
DWORD dwMsgThreadId;
if( !DuplicateHandle( 0, hNotifyEvent, 0, NULL, 0, FALSE, 0 ) )
{
ERR( "Unable to duplicate event handle\n" );
return 0;
}
/* FIXME: Should most likely store that thread handle */
CreateThread( NULL, /* Security attribs */
0, /* Stack */
DPLAYX_MSG_ThreadMain, /* Msg reception function */
(LPVOID)hNotifyEvent, /* Msg reception function parameter */
0, /* Flags */
&dwMsgThreadId /* Updated with thread id */
);
return dwMsgThreadId;
}
static DWORD CALLBACK DPLAYX_MSG_ThreadMain( LPVOID lpContext )
{
HANDLE hMsgEvent = (HANDLE)lpContext;
for ( ;; )
{
FIXME( "Ho Hum. Msg thread with nothing to do on handle %u\n", hMsgEvent );
SleepEx( 10000, FALSE ); /* 10 secs */
}
CloseHandle( hMsgEvent );
}
#ifndef __WINE_DPLAYX_MESSAGES
#define __WINE_DPLAYX_MESSAGES
#include "windef.h"
DWORD CreateMessageReceptionThread( HANDLE hNotifyEvent );
#endif
/* Helper functions for TAILQ functions defined in <sys/queue.h>
/* A queue definition based on sys/queue.h TAILQ definitions
*
* Blame any implementation mistakes on Peter Hunnisett
* <hunnise@nortelnetworks.com>
......@@ -8,50 +7,92 @@
#ifndef __WINE_DPLAYX_QUEUE_H
#define __WINE_DPLAYX_QUEUE_H
#include <sys/queue.h>
#define DPQ_INSERT(a,b,c) DPQ_INSERT_IN_TAIL(a,b,c)
/*
* Tail queue definitions.
*/
#define DPQ_HEAD(type) \
struct { \
struct type *lpQHFirst; /* first element */ \
struct type **lpQHLast; /* addr of last next element */ \
}
#define DPQ_ENTRY(type) \
struct { \
struct type *lpQNext; /* next element */ \
struct type **lpQPrev; /* address of previous next element */ \
}
/*
* Tail queue functions.
*/
#define DPQ_INIT(head) \
do{ \
(head).lpQHFirst = NULL; \
(head).lpQHLast = &(head).lpQHFirst; \
} while(0)
#define DPQ_INSERT_IN_TAIL(head, elm, field) \
do { \
(elm)->field.lpQNext = NULL; \
(elm)->field.lpQPrev = (head).lpQHLast; \
*(head).lpQHLast = (elm); \
(head).lpQHLast = &(elm)->field.lpQNext; \
} while(0)
#define DPQ_REMOVE(head, elm, field) \
do { \
if (((elm)->field.lpQNext) != NULL) \
(elm)->field.lpQNext->field.lpQPrev = \
(elm)->field.lpQPrev; \
else \
(head).lpQHLast = (elm)->field.lpQPrev; \
*(elm)->field.lpQPrev = (elm)->field.lpQNext; \
} while(0)
/* head - pointer to TAILQ_HEAD struct
/* head - pointer to DPQ_HEAD struct
* elm - how to find the next element
* field - to be concatenated to rc to compare with fieldToEqual
* fieldToEqual - The value that we're looking for
* rc - Variable to put the return code. Same type as (head)->tqh_first
* rc - Variable to put the return code. Same type as (head).lpQHFirst
*/
#define TAILQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc ) \
do { \
(rc) = (head)->tqh_first; /* NULL head? */ \
\
while( rc ) \
{ \
/* What we're searching for? */ \
if( (rc)->field == (fieldToEqual) ) \
{ \
break; /* rc == correct element */ \
} \
\
/* End of list check */ \
if( ( (rc) = (rc)->elm.tqe_next ) == (head)->tqh_first ) \
{ \
rc = NULL; \
break; \
} \
} \
#define DPQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc ) \
do { \
(rc) = (head).lpQHFirst; /* NULL head? */ \
\
while( rc ) \
{ \
/* What we're searching for? */ \
if( (rc)->field == (fieldToEqual) ) \
{ \
break; /* rc == correct element */ \
} \
\
/* End of list check */ \
if( ( (rc) = (rc)->elm.lpQNext ) == (head).lpQHFirst ) \
{ \
rc = NULL; \
break; \
} \
} \
} while(0)
/* head - pointer to TAILQ_HEAD struct
/* head - pointer to DPQ_HEAD struct
* elm - how to find the next element
* field - to be concatenated to rc to compare with fieldToEqual
* fieldToEqual - The value that we're looking for
* rc - Variable to put the return code. Same type as (head)->tqh_first
* rc - Variable to put the return code. Same type as (head).lpQHFirst
*/
#define TAILQ_REMOVE_ENTRY( head, elm, field, fieldToEqual, rc ) \
do { \
TAILQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc ); \
\
/* Was the element found? */ \
if( rc ) \
{ \
TAILQ_REMOVE( head, rc, elm ); \
} \
#define DPQ_REMOVE_ENTRY( head, elm, field, fieldToEqual, rc ) \
do { \
DPQ_FIND_ENTRY( head, elm, field, fieldToEqual, rc ); \
\
/* Was the element found? */ \
if( rc ) \
{ \
DPQ_REMOVE( head, rc, elm ); \
} \
} while(0)
#endif /* __WINE_DPLAYX_QUEUE_H */
......@@ -9,21 +9,41 @@ reasonably thourough description of what's going on.
Associated DirectX user header files are include/dplay.h, include/dplobby.h.
Implementation of the DPLAY and DPLAYX dlls are both in the dlls/dplayx
directory.
directory. Here's a brief description of the function of each of the files in that
directory:
dplay.c: Implementation of all the direct play object interfaces.
dplobby.c: Implementation of all the direct play lobby interfaces.
dpclassfactory.c: Implementation of the COM class factory which can create either
direct play lobby or direct play lobby interfaces.
dpinit.h: Header file so that dpclassfactory.c can access dplay and dplobby query
functions. Shouldn't be included by anything else.
dplayx_global.h,
dplayx_global.c: Implementation of all things which are associated with dplay on
the computer - ie shared resources and such. Methods in this
compilation unit should not call anything out side this unit.
compilation unit should not call anything out side this unit
excepting base windows services and an interface to start the
messaging thread.
name_server.h,
name_server.c: Implementation of all things which are associated with the name
server functionality
dplayx_main.c: LibMain executed for loading and unloading the dll. This will make
the call to dplayx_global.c to request initialization and destruction
of any global data.
dplayx_queue.h: Linked list implementation for dplay/dplobby. Based off of the BSD
version found in <sys/queue.h>
dplayx_messages.h,
dplayx_messages.c: Messaging interface required for both DirectPlay and
DirectPlayLobby.
Presently the architectural relationship between this files is a little shakey, but
isn't so sufficiently bad that it needs fixing yet.
......@@ -32,6 +52,12 @@ or direct play lobby will not work at this point. Priority will be to get
examples from the sdk running. Once they're at least partially working, I can
get down to trying to get some of the games working.
However, now that address separation is a reality, all binary samples provided
in the sdk can be used. I have had success spawning processes and one
directx7 example will allow creation of an app and allow another to join it.
Unfortunately, there isn't much for it to be able to do give the state of
inter lobby messaging.
A small issue will be the fact that DirectX 6.1(ie. DirectPlay4) introduces a layer of functionality
inside the DP objects which provide guaranteed protocol delivery. This is
even if the native protocol, IPX or modem for instance, doesn't guarantee it. I'm going to leave
......@@ -59,7 +85,7 @@ TODO:
- (done) Fix wine dplay.h and dplobby.h header files to allow apps to create the ansi versions
- (started) Port some WineLib test programs using sdk programs (both C and C++ progs)
- (done) Implement a lib main for the dplayx dll (required for RunApplication, etc.)
- Figure out how to share the global memory correctly
- (done)Figure out how to share the global memory correctly
- Ensure that all dll stubs are present and the ordinals are correct
- (started) Implementation of functionality
- Addition of DirectX 7.0 functionality for direct play (try to catch that moving train)
......@@ -75,6 +101,19 @@ TODO:
- Handles need to be correctly reference counted
- Need to check if we need to deallocate any list objects when destroying
dplay interface
- RunApplication process spawning needs to have correct syncronization.
- Need to get inter lobby messages working.
ENHANCEMENTS:
- Improve footprint and realtime blocking by setting up a seperate data share
between lobby application and client since there can be multiple apps per
client.
- Handle everything in UNICODE (as server does) and do conversions for ANSI
interfaces. Should cut down on dplayx code base and maintanability (marginally)
and could be used to improve efficiency of dialog with the server (it wouldn't
have to do ANSI<->UNICODE transformations).
Programs to make work:
- lserver.exe (from sdk)
......@@ -91,8 +130,7 @@ Next API to implement on a per SDK program basis:
- ?
dplaunch.exe
- IDirectPlayLobbyAImpl_RunApplication
(need address space separation or else rebuild all sdk examples)
- Just needs final process startup messages to be exchanged correctly!
lserver.exe
- IDirectPlayLobby2WImpl_Connect
......
......@@ -424,6 +424,9 @@ ICOM_DEFINE(IDirectPlayLobby3,IDirectPlayLobby2)
#define IDirectPlayLobby_UnregisterApplication(p,a,b) ICOM_CALL2(UnregisterApplication,p,a,b)
#define IDirectPlayLobby_WaitForConnectionSettings(p,a) ICOM_CALL1(WaitForConnectionSettings,p,a)
/* Used for WaitForConnectionSettings */
#define DPLWAIT_CANCEL 0x00000001
#ifdef __cplusplus
} /* extern "C" */
#endif /* defined(__cplusplus) */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment