- Added dplayx LibMain for initialization of all dplayx 'global' data

- Added start for global data manipulation
- TODO list updated
- Added some missing header file definitions
- Added the ansi versions of dplay and dplobby
- Fixed invalid macro for IDirectPlay4
- Cleaned up compiler warnings
- More implementation, bug fixes and critical region protection
This commit is contained in:
Peter Hunnisett 1999-11-04 02:17:03 +00:00 committed by Alexandre Julliard
parent a69bc02958
commit 88d89f93ea
10 changed files with 1713 additions and 568 deletions

View file

@ -9,7 +9,9 @@ SPEC_SRCS = dplay.spec dplayx.spec
C_SRCS = dplay.c \
dplobby.c \
dpclassfactory.c
dpclassfactory.c \
dplayx_main.c \
dplayx_global.c
all: $(MODULE).o

View file

@ -6,6 +6,7 @@
*
*/
#include <string.h>
#include "winerror.h"
#include "winnt.h"
#include "winreg.h"
@ -13,6 +14,8 @@
#include "heap.h"
#include "debugtools.h"
#include "dpinit.h"
DEFAULT_DEBUG_CHANNEL(dplay)
@ -27,13 +30,14 @@ typedef struct IDirectPlayImpl IDirectPlay4AImpl;
typedef struct IDirectPlayImpl IDirectPlay4Impl;
/* Forward declarations of virtual tables */
static ICOM_VTABLE(IDirectPlay2) directPlay2WVT;
static ICOM_VTABLE(IDirectPlay2) directPlay2AVT;
static ICOM_VTABLE(IDirectPlay3) directPlay3WVT;
static ICOM_VTABLE(IDirectPlay3) directPlay3AVT;
static ICOM_VTABLE(IDirectPlay4) directPlay4WVT;
static ICOM_VTABLE(IDirectPlay4) directPlay4AVT;
static ICOM_VTABLE(IDirectPlay2) directPlay2WVT;
static ICOM_VTABLE(IDirectPlay3) directPlay3WVT;
static ICOM_VTABLE(IDirectPlay4) directPlay4WVT;
/*****************************************************************************
* IDirectPlay implementation structure
*/
@ -50,6 +54,7 @@ struct IDirectPlayImpl
};
/* Get a new interface. To be used by QueryInterface. */
extern
HRESULT directPlay_QueryInterface
@ -71,7 +76,7 @@ HRESULT directPlay_QueryInterface
ICOM_VTBL(lpDP) = &directPlay2WVT;
InitializeCriticalSection( &lpDP->DP_lock );
IDirectPlayX_AddRef( lpDP );
IDirectPlayX_AddRef( (LPDIRECTPLAY2A)lpDP );
*ppvObj = lpDP;
@ -90,8 +95,9 @@ HRESULT directPlay_QueryInterface
}
ICOM_VTBL(lpDP) = &directPlay2AVT;
InitializeCriticalSection( &lpDP->DP_lock );
IDirectPlayX_AddRef( lpDP );
IDirectPlayX_AddRef( (LPDIRECTPLAY2A)lpDP );
*ppvObj = lpDP;
@ -110,8 +116,9 @@ HRESULT directPlay_QueryInterface
}
ICOM_VTBL(lpDP) = &directPlay3WVT;
InitializeCriticalSection( &lpDP->DP_lock );
IDirectPlayX_AddRef( lpDP );
IDirectPlayX_AddRef( (LPDIRECTPLAY2A)lpDP );
*ppvObj = lpDP;
@ -130,8 +137,9 @@ HRESULT directPlay_QueryInterface
}
ICOM_VTBL(lpDP) = &directPlay3AVT;
InitializeCriticalSection( &lpDP->DP_lock );
IDirectPlayX_AddRef( lpDP );
IDirectPlayX_AddRef( (LPDIRECTPLAY2A)lpDP );
*ppvObj = lpDP;
@ -150,8 +158,9 @@ HRESULT directPlay_QueryInterface
}
ICOM_VTBL(lpDP) = &directPlay4WVT;
InitializeCriticalSection( &lpDP->DP_lock );
IDirectPlayX_AddRef( lpDP );
IDirectPlayX_AddRef( (LPDIRECTPLAY2A)lpDP );
*ppvObj = lpDP;
@ -170,8 +179,9 @@ HRESULT directPlay_QueryInterface
}
ICOM_VTBL(lpDP) = &directPlay4AVT;
InitializeCriticalSection( &lpDP->DP_lock );
IDirectPlayX_AddRef( lpDP );
IDirectPlayX_AddRef( (LPDIRECTPLAY2A)lpDP );
*ppvObj = lpDP;
@ -859,29 +869,11 @@ static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
return DP_OK;
}
#if 0
typedef BOOL (CALLBACK* LPDPENUMDPCALLBACKA)(
LPGUID lpguidSP,
LPSTR lpSPName, /* ptr to str w/ driver description */
DWORD dwMajorVersion, /* Major # of driver spec in lpguidSP */
DWORD dwMinorVersion, /* Minor # of driver spec in lpguidSP */
LPVOID lpContext); /* User given */
typedef BOOL (CALLBACK* LPDPENUMCONNECTIONSCALLBACK)(
LPCGUID lpguidSP,
LPVOID lpConnection,
DWORD dwConnectionSize,
LPCDPNAME lpName,
DWORD dwFlags,
LPVOID lpContext);
#endif
static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
{
ICOM_THIS(IDirectPlay3Impl,iface);
FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
TRACE("(%p)->(%p,%p,%p,0x%08lx)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
/* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
if( dwFlags == 0 )
@ -896,21 +888,85 @@ static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
return DPERR_INVALIDFLAGS;
}
if( lpguidApplication != NULL )
if( !lpEnumCallback || !*lpEnumCallback )
{
FIXME( ": don't know how to deal with a non NULL lpguidApplication yet\n" );
return DPERR_INVALIDPARAMS;
}
/* Enumerate DirectPlay service providers */
if( dwFlags & DPCONNECTION_DIRECTPLAY )
{
HKEY hkResult;
LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
LPSTR guidDataSubKey = "Guid";
DWORD dwIndex, sizeOfSubKeyName=50;
char subKeyName[51];
/* Need to loop over the service providers in the registry */
if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
0, KEY_ENUMERATE_SUB_KEYS, &hkResult ) != ERROR_SUCCESS )
{
/* Hmmm. Does this mean that there are no service providers? */
ERR(": no service providers?\n");
return DP_OK;
}
/* Traverse all the service providers we have available */
for( dwIndex=0;
RegEnumKeyA( hkResult, dwIndex, subKeyName, sizeOfSubKeyName ) != ERROR_NO_MORE_ITEMS;
++dwIndex )
{
HKEY hkServiceProvider;
GUID serviceProviderGUID;
DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
char returnBuffer[51];
LPWSTR lpWGUIDString;
DPNAME dpName;
TRACE(" this time through: %s\n", subKeyName );
/* Get a handle for this particular service provider */
if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_QUERY_VALUE,
&hkServiceProvider ) != ERROR_SUCCESS )
{
ERR(": what the heck is going on?\n" );
continue;
}
if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
NULL, &returnTypeGUID, returnBuffer,
&sizeOfReturnBuffer ) != ERROR_SUCCESS )
{
ERR(": missing GUID registry data members\n" );
continue;
}
/* FIXME: Check return types to ensure we're interpreting data right */
lpWGUIDString = HEAP_strdupAtoW( GetProcessHeap(), 0, returnBuffer );
CLSIDFromString( (LPCOLESTR)lpWGUIDString, &serviceProviderGUID );
HeapFree( GetProcessHeap(), 0, lpWGUIDString );
/* FIXME: Have I got a memory leak on the serviceProviderGUID? */
dpName.dwSize = sizeof( dpName );
dpName.dwFlags = 0;
dpName.psn.lpszShortNameA = subKeyName; /* FIXME: Is this right? */
dpName.pln.lpszLongNameA = subKeyName; /* FIXME: Is this right? */
/* The enumeration will return FALSE if we are not to continue */
if( !lpEnumCallback( &serviceProviderGUID, NULL,0, &dpName, 0, lpContext ) )
{
WARN("lpEnumCallback returning FALSE\n" );
break;
}
}
}
/* Enumerate DirectPlayLobby service providers */
if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
{
FIXME( "DPCONNECTION_DIRECTPLAYLOBBY flag not handled\n" );
}
return DP_OK;
@ -961,6 +1017,12 @@ static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
{
ICOM_THIS(IDirectPlay3Impl,iface);
FIXME("(%p)->(%p,0x%08lx): stub\n", This, lpConnection, dwFlags );
if( dwFlags != 0 )
{
return DPERR_INVALIDFLAGS;
}
return DP_OK;
}
@ -1579,13 +1641,11 @@ HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback,
LPVOID lpContext )
{
HKEY hkResult;
HKEY hkResult;
LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
LPSTR guidDataSubKey = "Guid";
LPSTR majVerDataSubKey = "dwReserved1";
LPSTR minVerDataSubKey = "dwReserved0";
DWORD dwIndex, sizeOfSubKeyName=50;
char subKeyName[51];
DWORD dwIndex;
DWORD sizeOfSubKeyName=50;
char subKeyName[51];
TRACE(": lpEnumCallback=%p lpContext=%p\n", lpEnumCallback, lpContext );
@ -1608,6 +1668,9 @@ HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback,
RegEnumKeyA( hkResult, dwIndex, subKeyName, sizeOfSubKeyName ) != ERROR_NO_MORE_ITEMS;
++dwIndex )
{
LPSTR majVerDataSubKey = "dwReserved1";
LPSTR minVerDataSubKey = "dwReserved2";
LPSTR guidDataSubKey = "Guid";
HKEY hkServiceProvider;
GUID serviceProviderGUID;
DWORD returnTypeGUID, returnTypeReserved, sizeOfReturnBuffer = 50;
@ -1641,8 +1704,9 @@ HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback,
CLSIDFromString( (LPCOLESTR)lpWGUIDString, &serviceProviderGUID );
HeapFree( GetProcessHeap(), 0, lpWGUIDString );
/* FIXME: Need to know which of dwReserved1 and dwReserved2 are maj and min */
sizeOfReturnBuffer = 50;
if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
NULL, &returnTypeReserved, returnBuffer,
&sizeOfReturnBuffer ) != ERROR_SUCCESS )
@ -1651,17 +1715,14 @@ HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA lpEnumCallback,
continue;
}
/* FIXME: This couldn't possibly be right...*/
majVersionNum = GET_DWORD( returnBuffer );
sizeOfReturnBuffer = 50;
if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
NULL, &returnTypeReserved, returnBuffer,
&sizeOfReturnBuffer ) != ERROR_SUCCESS )
{
ERR(": missing dwReserved0 registry data members\n") ;
ERR(": missing dwReserved2 registry data members\n") ;
continue;
}
@ -1701,25 +1762,54 @@ HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID
HRESULT WINAPI DirectPlayCreate
( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk)
{
char lpGUIDString[51];
WINE_StringFromCLSID( lpGUID, &lpGUIDString[0] );
TRACE("lpGUID=%p lplpDP=%p pUnk=%p\n", lpGUID,lplpDP,pUnk);
TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", &lpGUIDString[0], lplpDP, pUnk );
if( pUnk != NULL )
{
/* Hmmm...wonder what this means! */
ERR("What does a NULL here mean?\n" );
return DPERR_OUTOFMEMORY;
return CLASS_E_NOAGGREGATION;
}
/* One possibility is that they want an exact dplay interface */
if( IsEqualGUID( &IID_IDirectPlay2A, lpGUID ) )
{
return directPlay_QueryInterface( lpGUID, lplpDP );
return directPlay_QueryInterface( lpGUID, (LPVOID*)lplpDP );
}
else if( IsEqualGUID( &IID_IDirectPlay2, lpGUID ) )
{
return directPlay_QueryInterface( lpGUID, lplpDP );
return directPlay_QueryInterface( lpGUID, (LPVOID*)lplpDP );
}
/* Unknown interface type */
return DPERR_NOINTERFACE;
/* Create an IDirectPlay object. We don't support that so we'll cheat and
give them an IDirectPlay2A object and hope that doesn't cause problems */
if( directPlay_QueryInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
{
return DPERR_UNAVAILABLE;
}
/* Bind the desired service provider */
if( IsEqualGUID( lpGUID, &DPSPGUID_MODEM ) )
{
FIXME( "Modem binding not supported yet\n" );
IDirectPlayX_Release( *lplpDP );
*lplpDP = NULL;
return DPERR_INVALIDPARAMS;
}
/* The GUID_NULL means don't bind a service provider. Just return the
interface. However, if it isn't we were given a bogus GUID, return an ERROR */
if( !IsEqualGUID( lpGUID, &GUID_NULL ) )
{
WARN( "unknown GUID %s\n", &lpGUIDString[0] );
}
IDirectPlayX_Release( *lplpDP );
*lplpDP = NULL;
return DPERR_INVALIDPARAMS;
}

View file

@ -1,5 +1,6 @@
name dplayx
type win32
init DPLAYX_LibMain
1 stdcall DirectPlayCreate(ptr ptr ptr ptr) DirectPlayCreate
2 stdcall DirectPlayEnumerateA(ptr ptr) DirectPlayEnumerateA

532
dlls/dplayx/dplayx_global.c Normal file
View file

@ -0,0 +1,532 @@
/* dplayx.dll global data implementation.
*
* Copyright 1999 - Peter Hunnisett
*
* <presently under construction - contact hunnise@nortelnetworks.com>
*
*/
/* NOTE: Methods that begin with DPLAYX_ are used for dealing with
* dplayx.dll data which is accessible from all processes.
*/
#include "debugtools.h"
#include "winbase.h"
#include "winerror.h"
#include "heap.h" /* Really shouldn't be using those HEAP_strdupA interfaces should I? */
#include "dplayx_global.h"
DEFAULT_DEBUG_CHANNEL(dplay)
/* FIXME: Need to do all that fun other dll referencing type of stuff */
/* FIXME: Need to allocate a giant static area - or a global data type thing for Get/Set */
/* Static data for all processes */
static LPSTR lpszDplayxSemaName = "DPLAYX_SM";
static HANDLE hDplayxSema;
#define DPLAYX_AquireSemaphore() 0L /* WaitForSingleObject( hDplayxSema, INFINITE? ) */
#define DPLAYX_ReleaseSemaphore() 0L /* ReleaseSemaphore( hDplayxSema, ..., ... ) */
/* HACK for simple global data right now */
enum { numSupportedLobbies = 32 };
typedef struct tagDirectPlayLobbyData
{
DWORD dwConnFlags;
DPSESSIONDESC2 sessionDesc;
DPNAME playerName;
GUID guidSP;
LPVOID lpAddress;
DWORD dwAddressSize;
DWORD dwAppID;
HANDLE hReceiveEvent;
} DirectPlayLobbyData, *lpDirectPlayLobbyData;
static DirectPlayLobbyData lobbyData[ numSupportedLobbies ];
/* Function prototypes */
BOOL DPLAYX_AppIdLobbied( DWORD dwAppId, lpDirectPlayLobbyData* dplData );
/***************************************************************************
* Called to initialize the global data. This will only be used on the
* loading of the dll
***************************************************************************/
void DPLAYX_ConstructData(void)
{
UINT i;
TRACE( "DPLAYX dll loaded - construct called\n" );
/* FIXME: This needs to be allocated shared */
hDplayxSema = CreateSemaphoreA( NULL, 0, 1, lpszDplayxSemaName );
if( !hDplayxSema )
{
/* Really don't have any choice but to continue... */
ERR( "Semaphore creation error 0x%08lx\n", GetLastError() );
}
/* Set all lobbies to be "empty" */
for( i=0; i < numSupportedLobbies; i++ )
{
lobbyData[ i ].dwAppID = 0;
}
}
/***************************************************************************
* Called to destroy all global data. This will only be used on the
* unloading of the dll
***************************************************************************/
void DPLAYX_DestructData(void)
{
/* Hmmm...what to call to delete the semaphore? Auto delete? */
TRACE( "DPLAYX dll unloaded - destruct called\n" );
}
/* NOTE: This must be called with the semaphore aquired.
* TRUE/FALSE with a pointer to it's data returned
*/
BOOL DPLAYX_AppIdLobbied( DWORD dwAppID, lpDirectPlayLobbyData* lplpDplData )
{
INT i;
if( dwAppID == 0 )
{
dwAppID = GetCurrentProcessId();
}
for( i=0; i < numSupportedLobbies; i++ )
{
if( lobbyData[ i ].dwAppID == dwAppID )
{
/* This process is lobbied */
*lplpDplData = &lobbyData[ i ];
return TRUE;
}
}
return FALSE;
}
#if !defined( WORKING_PROCESS_SUSPEND )
/* These two functions should not exist. We would normally create a process initially
suspended when we RunApplication. This gives us time to actually store some data
before the new process might try to read it. However, process suspension doesn't
work yet and I'm too stupid to get it going. So, we'll just hack in fine fashion */
DWORD DPLAYX_AquireSemaphoreHack( void )
{
return DPLAYX_AquireSemaphore();
}
DWORD DPLAYX_ReleaseSemaphoreHack( void )
{
return DPLAYX_ReleaseSemaphore();
}
#endif
/* Reserve a spot for the new appliction. TRUE means success and FALSE failure. */
BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent )
{
INT i;
DPLAYX_AquireSemaphore();
for( i=0; i < numSupportedLobbies; i++ )
{
if( lobbyData[ i ].dwAppID == 0 )
{
/* This process is now lobbied */
lobbyData[ i ].dwAppID = dwAppID;
lobbyData[ i ].hReceiveEvent = hReceiveEvent;
DPLAYX_ReleaseSemaphore();
return TRUE;
}
}
DPLAYX_ReleaseSemaphore();
return FALSE;
}
HRESULT DPLAYX_GetConnectionSettingsA
( DWORD dwAppID,
LPVOID lpData,
LPDWORD lpdwDataSize )
{
lpDirectPlayLobbyData lpDplData;
LPDPLCONNECTION lpDplConnection;
DPLAYX_AquireSemaphore();
if ( !DPLAYX_AppIdLobbied( dwAppID, &lpDplData ) )
{
DPLAYX_ReleaseSemaphore();
return DPERR_NOTLOBBIED;
}
/* Verify buffer size */
if ( ( lpData == NULL ) ||
( *lpdwDataSize < sizeof( DPLCONNECTION ) )
)
{
DPLAYX_ReleaseSemaphore();
*lpdwDataSize = sizeof( DPLCONNECTION );
return DPERR_BUFFERTOOSMALL;
}
/* Copy the information */
lpDplConnection = (LPDPLCONNECTION)lpData;
/* Copy everything we've got into here */
/* Need to actually store the stuff here. Check if we've already allocated each field first. */
lpDplConnection->dwSize = sizeof( DPLCONNECTION );
lpDplConnection->dwFlags = lpDplData->dwConnFlags;
/* Copy LPDPSESSIONDESC2 struct */
lpDplConnection->lpSessionDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->sessionDesc ) );
memcpy( lpDplConnection->lpSessionDesc, &lpDplData->sessionDesc, sizeof( lpDplData->sessionDesc ) );
if( lpDplData->sessionDesc.sess.lpszSessionNameA )
{
lpDplConnection->lpSessionDesc->sess.lpszSessionNameA =
HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.sess.lpszSessionNameA );
}
if( lpDplData->sessionDesc.pass.lpszPasswordA )
{
lpDplConnection->lpSessionDesc->pass.lpszPasswordA =
HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.pass.lpszPasswordA );
}
lpDplConnection->lpSessionDesc->dwReserved1 = lpDplData->sessionDesc.dwReserved1;
lpDplConnection->lpSessionDesc->dwReserved2 = lpDplData->sessionDesc.dwReserved2;
/* Copy DPNAME struct - seems to be optional - check for existance first */
lpDplConnection->lpPlayerName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->playerName ) );
memcpy( lpDplConnection->lpPlayerName, &(lpDplData->playerName), sizeof( lpDplData->playerName ) );
if( lpDplData->playerName.psn.lpszShortNameA )
{
lpDplConnection->lpPlayerName->psn.lpszShortNameA =
HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.psn.lpszShortNameA );
}
if( lpDplData->playerName.pln.lpszLongNameA )
{
lpDplConnection->lpPlayerName->pln.lpszLongNameA =
HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.pln.lpszLongNameA );
}
memcpy( &lpDplConnection->guidSP, &lpDplData->guidSP, sizeof( lpDplData->guidSP ) );
lpDplConnection->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->dwAddressSize );
memcpy( lpDplConnection->lpAddress, lpDplData->lpAddress, lpDplData->dwAddressSize );
lpDplConnection->dwAddressSize = lpDplData->dwAddressSize;
/* Send a message - or only the first time? */
DPLAYX_ReleaseSemaphore();
return DP_OK;
}
HRESULT DPLAYX_GetConnectionSettingsW
( DWORD dwAppID,
LPVOID lpData,
LPDWORD lpdwDataSize )
{
lpDirectPlayLobbyData lpDplData;
LPDPLCONNECTION lpDplConnection;
DPLAYX_AquireSemaphore();
if ( !DPLAYX_AppIdLobbied( dwAppID, &lpDplData ) )
{
DPLAYX_ReleaseSemaphore();
return DPERR_NOTLOBBIED;
}
/* Verify buffer size */
if ( ( lpData == NULL ) ||
( *lpdwDataSize < sizeof( DPLCONNECTION ) )
)
{
DPLAYX_ReleaseSemaphore();
*lpdwDataSize = sizeof( DPLCONNECTION );
return DPERR_BUFFERTOOSMALL;
}
/* Copy the information */
lpDplConnection = (LPDPLCONNECTION)lpData;
/* Copy everything we've got into here */
/* Need to actually store the stuff here. Check if we've already allocated each field first. */
lpDplConnection->dwSize = sizeof( DPLCONNECTION );
lpDplConnection->dwFlags = lpDplData->dwConnFlags;
/* Copy LPDPSESSIONDESC2 struct */
lpDplConnection->lpSessionDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->sessionDesc ) );
memcpy( lpDplConnection->lpSessionDesc, &lpDplData->sessionDesc, sizeof( lpDplData->sessionDesc ) );
if( lpDplData->sessionDesc.sess.lpszSessionName )
{
lpDplConnection->lpSessionDesc->sess.lpszSessionName =
HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.sess.lpszSessionName );
}
if( lpDplData->sessionDesc.pass.lpszPassword )
{
lpDplConnection->lpSessionDesc->pass.lpszPassword =
HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.pass.lpszPassword );
}
lpDplConnection->lpSessionDesc->dwReserved1 = lpDplData->sessionDesc.dwReserved1;
lpDplConnection->lpSessionDesc->dwReserved2 = lpDplData->sessionDesc.dwReserved2;
/* Copy DPNAME struct - seems to be optional - check for existance first */
lpDplConnection->lpPlayerName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->playerName ) );
memcpy( lpDplConnection->lpPlayerName, &(lpDplData->playerName), sizeof( lpDplData->playerName ) );
if( lpDplData->playerName.psn.lpszShortName )
{
lpDplConnection->lpPlayerName->psn.lpszShortName =
HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.psn.lpszShortName );
}
if( lpDplData->playerName.pln.lpszLongName )
{
lpDplConnection->lpPlayerName->pln.lpszLongName =
HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.pln.lpszLongName );
}
memcpy( &lpDplConnection->guidSP, &lpDplData->guidSP, sizeof( lpDplData->guidSP ) );
lpDplConnection->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->dwAddressSize );
memcpy( lpDplConnection->lpAddress, lpDplData->lpAddress, lpDplData->dwAddressSize );
lpDplConnection->dwAddressSize = lpDplData->dwAddressSize;
/* Send a message - or only the first time? */
DPLAYX_ReleaseSemaphore();
return DP_OK;
}
HRESULT DPLAYX_SetConnectionSettingsA
( DWORD dwFlags,
DWORD dwAppID,
LPDPLCONNECTION lpConn )
{
lpDirectPlayLobbyData lpDplData;
DPLAYX_AquireSemaphore();
if ( !DPLAYX_AppIdLobbied( dwAppID, &lpDplData ) )
{
/* FIXME: Create a new entry for this dwAppID? */
DPLAYX_ReleaseSemaphore();
return DPERR_GENERIC;
}
/* Paramater check */
if( dwFlags || !lpConn )
{
DPLAYX_ReleaseSemaphore();
ERR("invalid parameters.\n");
return DPERR_INVALIDPARAMS;
}
/* Store information */
if( lpConn->dwSize != sizeof(DPLCONNECTION) )
{
DPLAYX_ReleaseSemaphore();
ERR(": old/new DPLCONNECTION type? Size=%08lx vs. expected=%ul bytes\n",
lpConn->dwSize, sizeof( DPLCONNECTION ) );
return DPERR_INVALIDPARAMS;
}
/* Need to investigate the lpConn->lpSessionDesc to figure out
* what type of session we need to join/create.
*/
if( (!lpConn->lpSessionDesc ) ||
( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
)
{
DPLAYX_ReleaseSemaphore();
ERR("DPSESSIONDESC passed in? Size=%08lx vs. expected=%ul bytes\n",
lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) );
return DPERR_INVALIDPARAMS;
}
/* FIXME: How do I store this stuff so that it can be read by all processes? Static area? What about strings? Ewww...large global shared */
/* Need to actually store the stuff here. Check if we've already allocated each field first. */
lpDplData->dwConnFlags = lpConn->dwFlags;
/* Copy LPDPSESSIONDESC2 struct - this is required */
memcpy( &lpDplData->sessionDesc, lpConn->lpSessionDesc, sizeof( *(lpConn->lpSessionDesc) ) );
/* FIXME: Can this just be shorted? Does it handle the NULL case correctly? */
if( lpConn->lpSessionDesc->sess.lpszSessionNameA )
lpDplData->sessionDesc.sess.lpszSessionNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->sess.lpszSessionNameA );
else
lpDplData->sessionDesc.sess.lpszSessionNameA = NULL;
if( lpConn->lpSessionDesc->pass.lpszPasswordA )
lpDplData->sessionDesc.pass.lpszPasswordA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->pass.lpszPasswordA );
else
lpDplData->sessionDesc.pass.lpszPasswordA = NULL;
lpDplData->sessionDesc.dwReserved1 = lpConn->lpSessionDesc->dwReserved1;
lpDplData->sessionDesc.dwReserved2 = lpConn->lpSessionDesc->dwReserved2;
/* Copy DPNAME struct - seems to be optional - check for existance first */
if( lpConn->lpPlayerName )
{
memcpy( &lpDplData->playerName, lpConn->lpPlayerName, sizeof( *lpConn->lpPlayerName ) );
if( lpConn->lpPlayerName->psn.lpszShortNameA )
lpDplData->playerName.psn.lpszShortNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->psn.lpszShortNameA );
if( lpConn->lpPlayerName->pln.lpszLongNameA )
lpDplData->playerName.pln.lpszLongNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->pln.lpszLongNameA );
}
memcpy( &lpDplData->guidSP, &lpConn->guidSP, sizeof( lpConn->guidSP ) );
lpDplData->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->dwAddressSize );
memcpy( lpDplData->lpAddress, lpConn->lpAddress, lpConn->dwAddressSize );
lpDplData->dwAddressSize = lpConn->dwAddressSize;
/* Send a message - I think */
DPLAYX_ReleaseSemaphore();
return DP_OK;
}
HRESULT DPLAYX_SetConnectionSettingsW
( DWORD dwFlags,
DWORD dwAppID,
LPDPLCONNECTION lpConn )
{
lpDirectPlayLobbyData lpDplData;
DPLAYX_AquireSemaphore();
if ( !DPLAYX_AppIdLobbied( dwAppID, &lpDplData ) )
{
DPLAYX_ReleaseSemaphore();
return DPERR_NOTLOBBIED;
}
/* Paramater check */
if( dwFlags || !lpConn )
{
DPLAYX_ReleaseSemaphore();
ERR("invalid parameters.\n");
return DPERR_INVALIDPARAMS;
}
/* Store information */
if( lpConn->dwSize != sizeof(DPLCONNECTION) )
{
DPLAYX_ReleaseSemaphore();
ERR(": old/new DPLCONNECTION type? Size=%08lx vs. expected=%ul bytes\n",
lpConn->dwSize, sizeof( DPLCONNECTION ) );
return DPERR_INVALIDPARAMS;
}
/* Need to investigate the lpConn->lpSessionDesc to figure out
* what type of session we need to join/create.
*/
if( (!lpConn->lpSessionDesc ) ||
( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
)
{
DPLAYX_ReleaseSemaphore();
ERR("DPSESSIONDESC passed in? Size=%08lx vs. expected=%ul bytes\n",
lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) );
return DPERR_INVALIDPARAMS;
}
/* FIXME: How do I store this stuff so that it can be read by all processes? Static area? What about strings? Ewww...large global shared */
/* Need to actually store the stuff here. Check if we've already allocated each field first. */
lpDplData->dwConnFlags = lpConn->dwFlags;
/* Copy LPDPSESSIONDESC2 struct - this is required */
memcpy( &lpDplData->sessionDesc, lpConn->lpSessionDesc, sizeof( *(lpConn->lpSessionDesc) ) );
/* FIXME: Can this just be shorted? Does it handle the NULL case correctly? */
if( lpConn->lpSessionDesc->sess.lpszSessionName )
lpDplData->sessionDesc.sess.lpszSessionName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->sess.lpszSessionName );
else
lpDplData->sessionDesc.sess.lpszSessionName = NULL;
if( lpConn->lpSessionDesc->pass.lpszPassword )
lpDplData->sessionDesc.pass.lpszPassword = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->pass.lpszPassword );
else
lpDplData->sessionDesc.pass.lpszPassword = NULL;
lpDplData->sessionDesc.dwReserved1 = lpConn->lpSessionDesc->dwReserved1;
lpDplData->sessionDesc.dwReserved2 = lpConn->lpSessionDesc->dwReserved2;
/* Copy DPNAME struct - seems to be optional - check for existance first */
if( lpConn->lpPlayerName )
{
memcpy( &lpDplData->playerName, lpConn->lpPlayerName, sizeof( *lpConn->lpPlayerName ) );
if( lpConn->lpPlayerName->psn.lpszShortName )
lpDplData->playerName.psn.lpszShortName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->psn.lpszShortName );
if( lpConn->lpPlayerName->pln.lpszLongName )
lpDplData->playerName.pln.lpszLongName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->pln.lpszLongName );
}
memcpy( &lpDplData->guidSP, &lpConn->guidSP, sizeof( lpConn->guidSP ) );
lpDplData->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->dwAddressSize );
memcpy( lpDplData->lpAddress, lpConn->lpAddress, lpConn->dwAddressSize );
lpDplData->dwAddressSize = lpConn->dwAddressSize;
/* Send a message - I think */
DPLAYX_ReleaseSemaphore();
return DP_OK;
}

View file

@ -0,0 +1,27 @@
#ifndef __WINE_DPLAYX_GLOBAL
#define __WINE_DPLAYX_GLOBAL
#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_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent );
/* This is a hack to ensure synchronization during application spawn */
#if !defined( WORKING_PROCESS_SUSPEND )
DWORD DPLAYX_AquireSemaphoreHack( void );
DWORD DPLAYX_ReleaseSemaphoreHack( void );
#endif
#endif /* __WINE_DPLAYX_GLOBAL */

58
dlls/dplayx/dplayx_main.c Normal file
View file

@ -0,0 +1,58 @@
/*
* DPLAYX.DLL LibMain
*
* Copyright 1999 - Peter Hunnisett
*
* contact <hunnise@nortelnetworks.com>
*/
#include "winbase.h"
#include "debugtools.h"
#include "dplayx_global.h"
DEFAULT_DEBUG_CHANNEL(dplay)
static DWORD DPLAYX_dwProcessesAttached = 0;
BOOL WINAPI DPLAYX_LibMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
switch ( fdwReason )
{
case DLL_PROCESS_ATTACH:
{
if ( DPLAYX_dwProcessesAttached == 0 )
{
/* First instance perform construction of global processor data */
DPLAYX_ConstructData();
}
DPLAYX_dwProcessesAttached++;
break;
}
case DLL_PROCESS_DETACH:
{
DPLAYX_dwProcessesAttached--;
if ( DPLAYX_dwProcessesAttached == 0 )
{
/* Last instance perform destruction of global processor data */
DPLAYX_DestructData();
}
break;
}
case DLL_THREAD_ATTACH: /* Do nothing */
case DLL_THREAD_DETACH: /* Do nothing */
break;
default:
break;
}
return TRUE;
}

File diff suppressed because it is too large Load diff

View file

@ -32,34 +32,42 @@ TODO:
- (done) Create and move to correct dll directories (dplay and dplayx)
- (done) Implement dplay in terms of dplayx
- (started) Need a better internal implementation for the objects which scales and
preferably doesn't involve casting structures
preferably doesn't involve casting structures (dplobby done)
- (started) More generic initialization and destruction helper methods based off
the chosen internal implementation
- How to deal with all the incorrect interfaces for IUnknown methods. The standard
wine macros are incorrect in that they always give IUnknown* rather than DirectPlayLobby2A
for instance. Are we forced to cast?
- Implement a lib main for the dplayx dll
the chosen internal implementation (dplobby done)
- Use only windows routines where an equivalent is available
- (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
- Ensure that all dll stubs are present and the ordinals are correct
- Implementation of functionality
- (started)Implementation of functionality
- Addition of DirectX 7.0 functionality for direct play (try to catch that moving train)
- bug fixes ;)
- Implement some WineLib test programs using sdk programs as a skeleton
Programs to make work:
- lserver.exe (from sdk)
- override.exe (from sdk)
- dpchat.exe (from sdk)
- duel.exe (from sdk)
- dplaunch.exe (from sdk)
Next API to implement on a per program basis:
override.exe
- IDirectPlay3AImp_EnumConnections
- fixme:dplay:DirectPlayCreate Modem binding not supported yet
- DirectPlay3AImpl_InitializeConnection
- DirectPlay2AImpl_Open
- ?
dplaunch.exe
- IDirectPlayLobbyAImpl_EnumLocalApplications
- IDirectPlayLobby2AImpl_CreateCompoundAddress
- IDirectPlayLobbyAImpl_RunApplication
- ?
lserver.exe
- IDirectPlayLobby2WImpl_Connect
- fixme:dplay:DirectPlayCreate Modem binding not supported yet
- IDirectPlay3WImpl_CreatePlayer
- IDirectPlay3WImpl_CreateGroup
- IDirectPlay3WImpl_SetGroupData
@ -67,12 +75,19 @@ Next API to implement on a per program basis:
- ?
bellhop.exe
- DirectPlay3AImpl_EnumConnections
- DirectPlay3AImpl_EnumConnections (lobby applications)
- ?
dpslots.exe
- IDirectPlayLobbyAImpl_SetConnectionSettings
- IDirectPlayAImpl_EnumConnections
- IDirectPlayLobby3AImpl_ConnectEx
- ?
Other TODO:
- look at problem with parsing the resource file for dplaunch. wrc problem?
- I should be getting the dialog box to come up for dpchat when something is selected
Call OLE32.7: CoCreateInstance(010017f0,00000000,00000001,010017e0,010094b4) ret=01002f38 fs=0237
Call ADVAPI32.188: RegOpenKeyExA(80000002,5e08dd90 "Software\\Microsoft\\DirectPlay\\Compatibility",00000000,00020019,40e7f49c) ret=5e0b6e5a fs=0237
Peter Hunnisett - hunnise@nortelnetworks.com

View file

@ -384,6 +384,8 @@ typedef BOOL (CALLBACK* LPDPENUMSESSIONSCALLBACK2)(
DWORD dwFlags,
LPVOID lpContext );
#define DPESC_TIMEDOUT 0x00000001
#include "poppack.h"
/*****************************************************************************
@ -449,7 +451,7 @@ ICOM_DEFINE(IDirectPlay,IUnknown)
/*****************************************************************************
* IDirectPlay2 interface
* IDirectPlay2 and IDirectPlay2A interface
*/
#define ICOM_INTERFACE IDirectPlay2
#define IDirectPlay2_METHODS \
@ -525,7 +527,7 @@ ICOM_DEFINE(IDirectPlay2,IUnknown)
/*****************************************************************************
* IDirectPlay3 interface
* IDirectPlay3 and IDirectPlay3A interface
*/
#define ICOM_INTERFACE IDirectPlay3
#define IDirectPlay3_METHODS \
@ -602,11 +604,7 @@ ICOM_DEFINE(IDirectPlay3,IDirectPlay2)
#define IDirectPlay3_GetPlayerFlags(p,a,b) ICOM_CALL2(GetPlayerFlags,p,a,b)
/*****************************************************************************
* IDirectPlay4 interface - this is also known as IDirectPlayX. Apparently people
* are realizing that declaring all the darn interfaces as IDirectPlay{2,3,...} is
* just plain dumb. It's now going to be just IDirectPlayX since they're just macros
* anyways. That's good because I'm tired of typing these entries :)
* The compiler should catch any problems with invocation of invalid method :)
* IDirectPlay4 and IDirectPlay4A interface
*/
#define ICOM_INTERFACE IDirectPlay4
#define IDirectPlay4_METHODS \
@ -617,11 +615,10 @@ ICOM_DEFINE(IDirectPlay3,IDirectPlay2)
ICOM_METHOD2( HRESULT, CancelMessage, DWORD,, DWORD, ) \
ICOM_METHOD3( HRESULT, CancelPriority, DWORD,, DWORD,, DWORD, )
#define IDirectPlay4_IMETHODS
#define IDirectPlay4_IMETHODS \
IDirectPlay3_IMETHODS \
IDirectPlay4_METHODS
ICOM_DEFINE(IDirectPlay4,IDirectPlay3)
#undef ICOM_INTERFACE
/*** IUnknown methods ***/
@ -682,6 +679,7 @@ ICOM_DEFINE(IDirectPlay4,IDirectPlay3)
#define IDirectPlayX_CancelMessage(p,a,b) ICOM_CALL2(CancelMessage,a,b)
#define IDirectPlayX_CancelPriority(p,a,b,c) ICOM_CALL3(CancelPriority,a,b,c)
/* For DirectPlay::EnumConnections */
#define DPCONNECTION_DIRECTPLAY 0x00000001
#define DPCONNECTION_DIRECTPLAYLOBBY 0x00000002

View file

@ -34,7 +34,7 @@ DEFINE_GUID(IID_IDirectPlayLobby3, 0x2db72490, 0x652c, 0x11d1, 0xa7, 0xa8, 0x0,
typedef struct IDirectPlayLobby3 IDirectPlayLobby3, *LPDIRECTPLAYLOBBY3;
DEFINE_GUID(IID_IDirectPlayLobby3A, 0x2db72491, 0x652c, 0x11d1, 0xa7, 0xa8, 0x0, 0x0, 0xf8, 0x3, 0xab, 0xfc);
typedef struct IDirectPlayLobby3A IDirectPlayLobby3A, *LPDIRECTPLAYLOBBY3A;
typedef struct IDirectPlayLobby3 IDirectPlayLobby3A, *LPDIRECTPLAYLOBBY3A;
/*****************************************************************************
@ -223,7 +223,7 @@ DEFINE_GUID(DPAID_INet, 0xc4a54da0, 0xe0af, 0x11cf, 0x9c, 0x4e, 0x0, 0xa0, 0xc9,
DEFINE_GUID(DPAID_INetW, 0xe63232a0, 0x9dbf, 0x11d0, 0x9c, 0xc1, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e);
/* DPAID_INetPort {E4524541-8EA5-11d1-8A96-006097B01411}
* Chunk purpose: Chunk is a port number used for creating TCP and UDP sockets.
* Chunk purpose: Chunk is a port number used for creating TCP and UDP sockets. (WORD)
*/
DEFINE_GUID(DPAID_INetPort, 0xe4524541, 0x8ea5, 0x11d1, 0x8a, 0x96, 0x0, 0x60, 0x97, 0xb0, 0x14, 0x11);
@ -331,8 +331,8 @@ typedef struct tagDPAPPLICATIONDESC
extern HRESULT WINAPI DirectPlayLobbyCreateW(LPGUID, LPDIRECTPLAYLOBBY *, IUnknown *, LPVOID, DWORD );
extern HRESULT WINAPI DirectPlayLobbyCreateA(LPGUID, LPDIRECTPLAYLOBBYA *, IUnknown *, LPVOID, DWORD );
extern HRESULT WINAPI DirectPlayLobbyCreateW(LPGUID, LPDIRECTPLAYLOBBY*, IUnknown*, LPVOID, DWORD );
extern HRESULT WINAPI DirectPlayLobbyCreateA(LPGUID, LPDIRECTPLAYLOBBYA*, IUnknown*, LPVOID, DWORD );
@ -355,7 +355,7 @@ typedef BOOL (CALLBACK* LPDPLENUMLOCALAPPLICATIONSCALLBACK)(
#include "poppack.h"
/*****************************************************************************
* IDirectPlayLobby interface
* IDirectPlayLobby and IDirectPlayLobbyA interface
*/
#define ICOM_INTERFACE IDirectPlayLobby
#define IDirectPlayLobby_METHODS \
@ -377,7 +377,7 @@ ICOM_DEFINE(IDirectPlayLobby,IUnknown)
#undef ICOM_INTERFACE
/*****************************************************************************
* IDirectPlayLobby2 interface
* IDirectPlayLobby2 and IDirectPlayLobby2A interface
*/
#define ICOM_INTERFACE IDirectPlayLobby2
#define IDirectPlayLobby2_METHODS \
@ -389,9 +389,8 @@ ICOM_DEFINE(IDirectPlayLobby2,IDirectPlayLobby)
#undef ICOM_INTERFACE
/*****************************************************************************
* IDirectPlayLobby3 interface
* IDirectPlayLobby3 and IDirectPlayLobby3A interface
*/
#define ICOM_INTERFACE IDirectPlayLobby3
#define IDirectPlayLobby3_METHODS \
ICOM_METHOD4( HRESULT, ConnectEx, DWORD,, REFIID,, LPVOID *,, IUnknown *,) \
@ -405,11 +404,9 @@ ICOM_DEFINE(IDirectPlayLobby2,IDirectPlayLobby)
ICOM_DEFINE(IDirectPlayLobby3,IDirectPlayLobby2)
#undef ICOM_INTERFACE
/*** IUnknown methods ***/
#define IDirectPlayLobby_QueryInterface(p,a,b) ICOM_CALL2(QueryInterface,p,a,b)
#define IDirectPlayLobby_AddRef(p) ICOM_CALL (AddRef,p)
#define IDirectPlayLobby_Release(p) ICOM_CALL (Release,p)
/*** IDirectPlayLobby methods ***/
#define IDirectPlayLobby_Connect(p,a,b,c) ICOM_CALL3(Connect,p,a,b,c)
#define IDirectPlayLobby_ConnectEx(p,a,b,c,d) ICOM_CALL4(ConnectEx,p,a,b,c,d)
#define IDirectPlayLobby_CreateAddress(p,a,b,c,d,e,f) ICOM_CALL6(CreateAddress,p,a,b,c,d,e,f)