On #winehackers the other day, kblin asked about whether TransGaming had
a Direct Play implementation. The answer is that we have something that
was worked on for a while but never completed. We have had some partial
success with it in the initial connection stages, but never pushed it
much beyond that.
Enclosed here is a patch to today's WineHQ git tree with our dpnet
implementation in the hopes that someone finds it useful. Beyond
ensuring that it compiles and links, it has not been tested at all with
WineHQ.
--
Gavriel State
Founder & CTO
TransGaming Inc.
gav@transgaming.com
http://www.transgaming.com
Broadening The Playing Field
diff --git a/dlls/dpnet/Makefile.in b/dlls/dpnet/Makefile.in
index 17929ea..e561796 100644
--- a/dlls/dpnet/Makefile.in
+++ b/dlls/dpnet/Makefile.in
@@ -4,18 +4,26 @@ SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = dpnet.dll
IMPORTLIB = libdpnet.$(IMPLIBEXT)
-IMPORTS = ole32 user32 advapi32 kernel32
+IMPORTS = ole32 user32 advapi32 kernel32 ws2_32 shlwapi
EXTRALIBS = -ldxguid -luuid
-C_SRCS = \
- address.c \
+C_SRCS = dpnet_main.c \
+ dpnet_classfactory.c \
client.c \
- dpnet_main.c \
peer.c \
- regsvr.c \
- server.c
+ server.c \
+ lobbiedapp.c \
+ lobbyclient.c \
+ address.c \
+ general.c \
+ threadpool.c \
+ sp_tcpip.c \
+ session.c \
+ dialog.c \
+ debug.c \
+ parse.c
-RC_SRCS = version.rc
+RC_SRCS = hostname_En.rc version.rc
@MAKE_DLL_RULES@
diff --git a/dlls/dpnet/address.c b/dlls/dpnet/address.c
index 0e45b80..a689b53 100644
--- a/dlls/dpnet/address.c
+++ b/dlls/dpnet/address.c
@@ -1,7 +1,7 @@
-/*
- * DirectPlay8 Address
- *
- * Copyright 2004 Raphael Junqueira
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -16,260 +16,899 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
*/
-#include "config.h"
-
#include <stdarg.h>
-
-#define COBJMACROS
+#include <string.h>
+#include <stdio.h>
#include "windef.h"
#include "winbase.h"
-#include "wingdi.h"
#include "winuser.h"
+#include "winreg.h"
#include "objbase.h"
#include "wine/debug.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "wine/unicode.h"
+
+#define NO_SHLWAPI_STREAM
+#include "shlwapi.h"
#include "dplay8.h"
-#include "dpnet_private.h"
+#include "dpaddr.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+static ICOM_VTABLE(IDirectPlay8Address) directPlay8AddressVT;
+static ICOM_VTABLE(IDirectPlay8AddressIP) directPlay8AddressIPVT;
+static DWORD GetDataType(const WCHAR * name);
+
+typedef struct dpna_types_t {
+ int index;
+ const WCHAR * name;
+ DWORD type;
+} dpna_types_t;
+
+static dpna_types_t dpna_types[] = {
+ { 0, DPNA_KEY_PROVIDER, DPNA_DATATYPE_GUID },
+ { 1, DPNA_KEY_APPLICATION_INSTANCE, DPNA_DATATYPE_GUID },
+ { 2, DPNA_KEY_HOSTNAME, DPNA_DATATYPE_STRING },
+ { 3, DPNA_KEY_BAUD, DPNA_DATATYPE_DWORD },
+ { 4, DPNA_KEY_DEVICE, DPNA_DATATYPE_GUID },
+ { 5, DPNA_KEY_FLOWCONTROL, DPNA_DATATYPE_STRING },
+ { 6, DPNA_KEY_NAMEINFO, DPNA_DATATYPE_STRING },
+ { 7, DPNA_KEY_NAT_RESOLVER, DPNA_DATATYPE_STRING },
+ { 8, DPNA_KEY_NAT_RESOLVER_USER_STRING, DPNA_DATATYPE_STRING },
+ { 9, DPNA_KEY_PARITY, DPNA_DATATYPE_STRING },
+ { 10, DPNA_KEY_PHONENUMBER, DPNA_DATATYPE_STRING },
+ { 11, DPNA_KEY_PORT, DPNA_DATATYPE_DWORD },
+ { 12, DPNA_KEY_PROGRAM, DPNA_DATATYPE_GUID },
+ { 13, DPNA_KEY_SCOPE, DPNA_DATATYPE_DWORD },
+ { 14, DPNA_KEY_STOPBITS, DPNA_DATATYPE_DWORD },
+ { 15, DPNA_KEY_TRAVERSALMODE, DPNA_DATATYPE_DWORD }
+};
-WINE_DEFAULT_DEBUG_CHANNEL(dpnet);
+#define MAX_DPNA_TYPES 16
-/* IDirectPlay8Address IUnknown parts follow: */
-static HRESULT WINAPI IDirectPlay8AddressImpl_QueryInterface(PDIRECTPLAY8ADDRESS iface, REFIID riid, LPVOID *ppobj)
+/* convert a guid to a wstr */
+static void guid2wstr(const GUID *guid, LPWSTR wstr)
{
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
+ char str[40];
- if (IsEqualGUID(riid, &IID_IUnknown)
- || IsEqualGUID(riid, &IID_IDirectPlay8Address)) {
- IUnknown_AddRef(iface);
- *ppobj = This;
- return DPN_OK;
+ sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ guid->Data1, guid->Data2, guid->Data3,
+ guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
+ guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+
+ MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, 40);
+}
+
+HRESULT WINAPI DirectPlay8Address_QueryInterface(PDIRECTPLAY8ADDRESS iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDirectPlay8Address, riid))
+ {
+ This->ref++;
+ *obj = This;
+ return S_OK;
+ }
+ else if (IsEqualGUID(&IID_IDirectPlay8AddressIP, riid))
+ {
+ This->ref++;
+ *obj = (LPVOID *)&This->lpVtbl2;
+ return S_OK;
}
+ else
+ {
+ FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj);
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG WINAPI DirectPlay8Address_AddRef(PDIRECTPLAY8ADDRESS iface)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ return ++This->ref;
+}
+
+ULONG WINAPI DirectPlay8Address_Release(PDIRECTPLAY8ADDRESS iface)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ if (--This->ref) return This->ref;
+
+ if (This->spData && !This->spDataRelease) FIXME("no release for data @ %p\n", This->spData);
+ if (This->spData) This->spDataRelease(This->spData);
+ while (This->component != NULL) {
+ struct AddressComponent * component = This->component;
+ This->component = This->component->next;
+ HeapFree(GetProcessHeap(), 0, component->pwszName);
+ HeapFree(GetProcessHeap(), 0, component->lpvData);
+ HeapFree(GetProcessHeap(), 0, component);
+ }
+ if (This->dwDataSize > 0) {
+ HeapFree(GetProcessHeap(), 0, This->pvUserData);
+ }
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+}
- WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
- return E_NOINTERFACE;
+HRESULT WINAPI DirectPlay8Address_BuildFromURLA(PDIRECTPLAY8ADDRESS iface, CHAR *pszSourceURL)
+{
+ /* ICOM_THIS(IDirectPlay8AddressImpl, iface); */
+
+ WCHAR *pwszSourceURL;
+ INT iUrlStringLen;
+ HRESULT hr;
+
+ TRACE("(%p)->(%s)\n", iface, debugstr_a(pszSourceURL));
+
+ iUrlStringLen = strlen(pszSourceURL);
+ pwszSourceURL = HeapAlloc(GetProcessHeap(), 0, (iUrlStringLen + 1) * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, pszSourceURL, iUrlStringLen, pwszSourceURL,
+ (iUrlStringLen + 1) * sizeof(WCHAR) / sizeof(CHAR));
+
+ hr = IDirectPlay8Address_BuildFromURLW(iface, pwszSourceURL);
+
+ HeapFree(GetProcessHeap(), 0, pwszSourceURL);
+
+ return hr;
}
-static ULONG WINAPI IDirectPlay8AddressImpl_AddRef(PDIRECTPLAY8ADDRESS iface) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- ULONG refCount = InterlockedIncrement(&This->ref);
+HRESULT WINAPI DirectPlay8Address_BuildFromURLW(PDIRECTPLAY8ADDRESS iface, WCHAR *pwszSourceURL)
+{
+ /*ICOM_THIS(IDirectPlay8AddressImpl, iface);*/
+ WCHAR *provider = NULL;
+ DWORD providerLen = 0;
+ GUID guidSP;
+ int i;
+
+ TRACE("(%p)->(%s)\n", iface, debugstr_w(pwszSourceURL));
- TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
+ if (strncmpW(pwszSourceURL, DPNA_HEADER, strlenW(DPNA_HEADER)) != 0)
+ return DPNERR_INVALIDURL;
- return refCount;
+ /* First, clear the old data out*/
+ IDirectPlay8Address_Clear(iface);
+
+ if (DPNET_GetKeyValueW(pwszSourceURL, DPNA_KEY_PROVIDER, provider, &providerLen)
+ != DPNERR_BUFFERTOOSMALL)
+ {
+ return DPNERR_INVALIDURL;
+ }
+
+ provider = HeapAlloc(GetProcessHeap(), 0, providerLen * sizeof(WCHAR));
+ DPNET_GetKeyValueW(pwszSourceURL, DPNA_KEY_PROVIDER, provider, &providerLen);
+ UrlUnescapeW(provider, NULL, NULL, URL_UNESCAPE_INPLACE);
+ CLSIDFromString(provider, &guidSP);
+ HeapFree(GetProcessHeap(), 0, provider);
+ IDirectPlay8Address_SetSP(iface, &guidSP);
+
+ /* start at 1 so we skip the provider we just added */
+ for (i = 1; i < MAX_DPNA_TYPES; i++) {
+ WCHAR attr[128];
+ void * datum = NULL;
+ DWORD len = 0;
+ DWORD type;
+
+ strcpyW(attr, dpna_types[i].name);
+ type = dpna_types[i].type;
+ if (DPNET_GetKeyValueW(pwszSourceURL, (const WCHAR *)attr, NULL,
+ &len) == DPNERR_BUFFERTOOSMALL)
+ {
+ datum = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ DPNET_GetKeyValueW(pwszSourceURL, attr, datum, &len);
+ IDirectPlay8Address_AddComponent(iface, attr, datum, len, type);
+ HeapFree(GetProcessHeap(), 0, datum);
+ }
+ }
+
+ return S_OK;
}
-static ULONG WINAPI IDirectPlay8AddressImpl_Release(PDIRECTPLAY8ADDRESS iface) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- ULONG refCount = InterlockedDecrement(&This->ref);
+HRESULT WINAPI DirectPlay8Address_Duplicate(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS *ppdpaNewAddress)
+{
+ /* ICOM_THIS(IDirectPlay8AddressImpl, iface); */
+ HRESULT hr;
+
+ TRACE("(%p)->(%p)\n", iface, ppdpaNewAddress);
+ hr = DPNET_CreateDirectPlay8Address(NULL, &IID_IDirectPlay8Address, (LPVOID *) ppdpaNewAddress);
+ if (!SUCCEEDED(hr))
+ {
+ TRACE("duplication failed\n");
+ return hr;
+ }
- TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
+ hr = IDirectPlay8Address_SetEqual(*ppdpaNewAddress, iface);
- if (!refCount) {
- HeapFree(GetProcessHeap(), 0, This);
+ if (!SUCCEEDED(hr))
+ {
+ IDirectPlay8Address_Release(*ppdpaNewAddress);
+ *ppdpaNewAddress = NULL;
+ TRACE("duplication failed\n");
+ return hr;
}
- return refCount;
+
+ TRACE("duplicated\n");
+
+ return hr;
}
-/* IDirectPlay8Address Interface follow: */
+HRESULT WINAPI DirectPlay8Address_SetEqual(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS pdpaAddress)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+ IDirectPlay8AddressImpl *otherThis = (IDirectPlay8AddressImpl *)pdpaAddress;
+ struct AddressComponent *comp;
+ struct AddressComponent *last;
+
+ TRACE("(%p)->(%p)\n", iface, pdpaAddress);
+
+ IDirectPlay8Address_Clear(iface);
-static HRESULT WINAPI IDirectPlay8AddressImpl_BuildFromURLW(PDIRECTPLAY8ADDRESS iface, WCHAR* pwszSourceURL) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %s): stub\n", This, debugstr_w(pwszSourceURL));
- return DPN_OK;
+ memcpy(&This->guidSP, &otherThis->guidSP, sizeof(GUID));
+ memcpy(&This->guidDevice, &otherThis->guidDevice, sizeof(GUID));
+
+ comp = otherThis->component;
+ last = NULL;
+ while (comp) {
+ struct AddressComponent *component;
+ component = HeapAlloc(GetProcessHeap(), 0, sizeof(struct AddressComponent));
+ component->pwszName = HeapAlloc(GetProcessHeap(), 0, (strlenW(comp->pwszName)+1) * sizeof(WCHAR));
+ component->lpvData = HeapAlloc(GetProcessHeap(), 0, comp->dwDataSize);
+ component->dwDataSize = comp->dwDataSize;
+ component->dwDataType = comp->dwDataType;
+ strcpyW(component->pwszName, comp->pwszName);
+ memcpy(component->lpvData, comp->lpvData, component->dwDataSize);
+
+ component->next = NULL;
+
+ if (last) last->next = component;
+ else This->component = component;
+ last = component;
+
+ comp = comp->next;
+ }
+
+ if (otherThis->spData) otherThis->spDataDuplicate(iface, otherThis->spData);
+
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_BuildFromURLA(PDIRECTPLAY8ADDRESS iface, CHAR* pszSourceURL) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %s): stub\n", This, pszSourceURL);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_IsEqual(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS pdpaAddress)
+{
+ /* ICOM_THIS(IDirectPlay8AddressImpl, iface); */
+ /* IDirectPlay8AddressImpl *otherThis = (IDirectPlay8AddressImpl *)pdpaAddress; */
+
+ FIXME("(%p)->(%p): stub\n", iface, pdpaAddress);
+
+ return DPNSUCCESS_NOTEQUAL;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_Duplicate(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS* ppdpaNewAddress) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %p): stub\n", This, ppdpaNewAddress);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_Clear(PDIRECTPLAY8ADDRESS iface)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->()\n", iface);
+
+ while (This->component != NULL) {
+ struct AddressComponent * component = This->component;
+ This->component = This->component->next;
+ HeapFree(GetProcessHeap(), 0, component->pwszName);
+ HeapFree(GetProcessHeap(), 0, component->lpvData);
+ HeapFree(GetProcessHeap(), 0, component);
+ }
+ if (This->dwDataSize > 0) {
+ HeapFree(GetProcessHeap(), 0, This->pvUserData);
+ This->dwDataSize = 0;
+ }
+
+ if (This->spData) This->spDataRelease(This->spData);
+ This->spData = NULL;
+
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_SetEqual(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS pdpaAddress) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %p): stub\n", This, pdpaAddress);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_GetURLW(PDIRECTPLAY8ADDRESS iface, WCHAR *pwszURL, PDWORD pdwNumChars)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+ DWORD numCharsRequired = 0;
+ WCHAR * url = NULL;
+ DWORD i = 1;
+ DWORD urlsize = 0;
+ struct AddressComponent *component;
+ WCHAR wide[1024];
+ WCHAR equals[] = {'=', 0};
+ WCHAR pound[] = {'#', 0};
+ WCHAR semicolon[] = {';', 0};
+
+ TRACE("(%p)->(%p, %p (%i))\n", iface, pwszURL, pdwNumChars, *pdwNumChars);
+
+ /* If no GUID is set or no components have been added, we're done */
+ if (IsEqualGUID(&This->guidSP, &GUID_NULL) || This->component == NULL) {
+ return DPNERR_INVALIDURL;
+ }
+
+ /* First compute the size of the URL. This is a pretty rough "guess" and
+ * will likely be a tad too big but we'll get the "right" number later. */
+ component = This->component;
+ while (component != NULL) {
+ if (component->dwDataType == GetDataType(component->pwszName)) {
+ urlsize += component->dwDataSize;
+ urlsize += strlenW(component->pwszName) + 2; /* include = and ; */
+ if (component->dwDataType == DPNA_DATATYPE_GUID) {
+ urlsize += 6; /* handle escaping */
+ }
+ }
+ component = component->next;
+ }
+
+ urlsize += 46; /* for the escaped provider GUID */
+ urlsize += strlenW(DPNA_HEADER) + 2; /* include /: */
+ urlsize += strlenW(DPNA_KEY_PROVIDER) + 2; /* include = and ; */
+ urlsize += This->dwDataSize; /* user data */
+
+ /* This should always be true, but should still check it */
+ if (urlsize > 0) {
+ DWORD needed = 46;
+ url = HeapAlloc(GetProcessHeap(), 0, urlsize * sizeof(WCHAR));
+
+ strcpyW(url, DPNA_HEADER); /* x-directplay:/ */
+ strcatW(url, DPNA_KEY_PROVIDER); /* provider */
+ strcatW(url, equals);
+
+ StringFromGUID2(&This->guidSP, wide, sizeof(wide));
+ UrlEscapeW(wide, url + strlenW(url), &needed, 0);
+
+ strcatW(url, semicolon);
+ component = This->component;
+
+ while (component != NULL) {
+ strcatW(url, component->pwszName);
+ strcatW(url, equals);
+ switch (component->dwDataType) {
+ case DPNA_DATATYPE_STRING:
+ strcatW(url, component->lpvData);
+ break;
+ case DPNA_DATATYPE_DWORD:
+ {
+ const WCHAR fmt[] = {'%', 'l', 'd', 0};
+ wsprintfW(wide, fmt, *((const DWORD *)component->lpvData));
+ strcatW(url, wide);
+ break;
+ }
+ case DPNA_DATATYPE_GUID:
+ {
+ guid2wstr((GUID*)component->lpvData, wide);
+ strcatW(url, wide);
+ }
+ default:
+ WARN("Unhandled data type %d\n", component->dwDataType);
+ break;
+ }
+ strcatW(url, semicolon);
+ i++;
+ component = component->next;
+ } /* while */
+ }
+
+ /* remove the trailing semi-colon */
+ url[strlenW(url)-1] = '\0';
+
+ if (This->dwDataSize > 0) {
+ strcatW(url, pound);
+ strcatW(url, This->pvUserData);
+ }
+
+ numCharsRequired = strlenW(url) + 1; /* null term */
+ if (*pdwNumChars < numCharsRequired)
+ {
+ *pdwNumChars = numCharsRequired;
+ HeapFree(GetProcessHeap(), 0, url);
+ return DPNERR_BUFFERTOOSMALL;
+ }
+ if (pwszURL != NULL)
+ {
+ strcpyW(pwszURL, url);
+ *pdwNumChars = numCharsRequired;
+ }
+ HeapFree(GetProcessHeap(), 0, url);
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_IsEqual(PDIRECTPLAY8ADDRESS iface, PDIRECTPLAY8ADDRESS pdpaAddress) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %p): stub\n", This, pdpaAddress);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_GetURLA(PDIRECTPLAY8ADDRESS iface, CHAR *pszURL, PDWORD pdwNumChars)
+{
+ /* ICOM_THIS(IDirectPlay8AddressImpl, iface); */
+ DWORD numCharsRequired = 0;
+ WCHAR * url = NULL;
+ HRESULT hr;
+
+ TRACE("(%p)->(%p, %p (%i))\n", iface, pszURL, pdwNumChars, *pdwNumChars);
+
+ hr = IDirectPlay8Address_GetURLW(iface, NULL, &numCharsRequired);
+ if (hr != S_OK && hr != DPNERR_BUFFERTOOSMALL) return hr;
+
+ url = HeapAlloc(GetProcessHeap(), 0, numCharsRequired * sizeof(WCHAR));
+ hr = IDirectPlay8Address_GetURLW(iface, url, &numCharsRequired);
+ if (hr == S_OK) {
+ INT len = WideCharToMultiByte(CP_ACP, 0, url, numCharsRequired, NULL, 0, NULL, NULL);
+ if (*pdwNumChars < len) {
+ *pdwNumChars = len;
+ hr = DPNERR_BUFFERTOOSMALL;
+ } else
+ if (pszURL) {
+ WideCharToMultiByte(CP_ACP, 0, url, numCharsRequired, pszURL, *pdwNumChars, NULL, NULL);
+ *pdwNumChars = len;
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, url);
+ return hr;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_Clear(PDIRECTPLAY8ADDRESS iface) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_GetSP(PDIRECTPLAY8ADDRESS iface, GUID *pguidSP)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%s)\n", iface, debugstr_guid(pguidSP));
+
+ if (IsEqualGUID(&This->guidSP, &GUID_NULL)) {
+ return DPNERR_DOESNOTEXIST;
+ }
+ memcpy(pguidSP, &This->guidSP, sizeof(GUID));
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_GetURLW(PDIRECTPLAY8ADDRESS iface, WCHAR* pwszURL, PDWORD pdwNumChars) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_GetUserData(PDIRECTPLAY8ADDRESS iface,
+ void *pvUserData,
+ PDWORD pdwBufferSize
+)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%p, %p)\n", iface, pvUserData, pdwBufferSize);
+
+ if (pvUserData == NULL && pdwBufferSize == 0) {
+ *pdwBufferSize = This->dwDataSize;
+ return DPNERR_BUFFERTOOSMALL;
+ } else {
+ if (*pdwBufferSize < This->dwDataSize) {
+ *pdwBufferSize = This->dwDataSize;
+ return DPNERR_BUFFERTOOSMALL;
+ }
+ memcpy(pvUserData, This->pvUserData, This->dwDataSize);
+ /* Size only gets set when in "query" mode */
+ if (*pdwBufferSize == 0)
+ *pdwBufferSize = This->dwDataSize;
+ }
+
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_GetURLA(PDIRECTPLAY8ADDRESS iface, CHAR* pszURL, PDWORD pdwNumChars) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_SetSP(PDIRECTPLAY8ADDRESS iface, const GUID *const pguidSP)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%s)\n", iface, debugstr_guid(pguidSP));
+ memcpy(&This->guidSP, pguidSP, sizeof(GUID));
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_GetSP(PDIRECTPLAY8ADDRESS iface, GUID* pguidSP) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %p)\n", iface, pguidSP);
- memcpy(pguidSP, &This->SP_guid, sizeof(GUID));
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_SetUserData(PDIRECTPLAY8ADDRESS iface,
+ const void *const pvUserData,
+ const DWORD dwDataSize)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%s, %d)\n", iface, debugstr_w(pvUserData), dwDataSize);
+
+ if (pvUserData == NULL && dwDataSize != 0)
+ return DPNERR_NOTALLOWED;
+
+ if (This->dwDataSize > 0) {
+ HeapFree(GetProcessHeap(), 0, This->pvUserData);
+ This->dwDataSize = 0;
+ }
+ if (pvUserData != NULL) {
+ This->pvUserData = HeapAlloc(GetProcessHeap(), 0, dwDataSize);
+ memcpy(This->pvUserData, (void *)pvUserData, dwDataSize);
+ } else {
+ This->pvUserData = NULL;
+ }
+ This->dwDataSize = dwDataSize;
+
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_GetUserData(PDIRECTPLAY8ADDRESS iface, LPVOID pvUserData, PDWORD pdwBufferSize) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_GetNumComponents(PDIRECTPLAY8ADDRESS iface, PDWORD pdwNumComponents)
+{
+ DWORD count = 1; /* DX9 returns the # of components +1 for some reason */
+ struct AddressComponent *c;
+
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%p)\n", iface, pdwNumComponents);
+
+ c = This->component;
+
+ while (c != NULL) {
+ count++;
+ c = c->next;
+ }
+
+ TRACE("count: %d\n", count);
+
+ *pdwNumComponents = count;
+
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_SetSP(PDIRECTPLAY8ADDRESS iface, CONST GUID* CONST pguidSP) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %s)\n", iface, debugstr_SP(pguidSP));
- memcpy(&This->SP_guid, pguidSP, sizeof(GUID));
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_GetComponentByName(PDIRECTPLAY8ADDRESS iface,
+ const WCHAR *const pwszName,
+ void *pvBuffer,
+ PDWORD pdwBufferSize,
+ PDWORD pdwDataType)
+{
+ struct AddressComponent *component;
+ HRESULT ret = DPNERR_DOESNOTEXIST;
+
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%s, %p, %p (%d), %p)\n", iface,
+ debugstr_w(pwszName), pvBuffer, pdwBufferSize,
+ *pdwBufferSize, pdwDataType);
+
+ if (pdwBufferSize == NULL)
+ return DPNERR_INVALIDPARAM;
+
+ component = This->component;
+
+ while (component != NULL) {
+ if (!strcmpW(component->pwszName, pwszName)) {
+ if (*pdwBufferSize >= component->dwDataSize) {
+ *pdwDataType = component->dwDataType;
+ if (component->dwDataType == DPNA_DATATYPE_STRING) {
+ strcpyW(pvBuffer, component->lpvData);
+ } else
+ memcpy(pvBuffer, component->lpvData, component->dwDataSize);
+ ret = S_OK;
+ } else {
+ ret = DPNERR_BUFFERTOOSMALL;
+ }
+ *pdwBufferSize = component->dwDataSize;
+ break;
+ }
+ component = component->next;
+ }
+
+ TRACE("returning %x\n", ret);
+ return ret;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_SetUserData(PDIRECTPLAY8ADDRESS iface, CONST void* CONST pvUserData, CONST DWORD dwDataSize) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_GetComponentByIndex(PDIRECTPLAY8ADDRESS iface,
+ const DWORD dwComponentID,
+ WCHAR *pwszName,
+ PDWORD pdwNameLen,
+ void *pvBuffer,
+ PDWORD pdwBufferSize,
+ PDWORD pdwDataType
+)
+{
+ struct AddressComponent *component;
+ HRESULT ret = DPNERR_DOESNOTEXIST;
+ int i = 0;
+
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%d, %p, %p, %p, %p, %p)\n", iface, dwComponentID,
+ pwszName, pdwNameLen, pvBuffer, pdwBufferSize,
+ pdwDataType);
+
+ if (pdwBufferSize == NULL || pdwNameLen == NULL)
+ return DPNERR_INVALIDPARAM;
+
+ component = This->component;
+
+ while (component != NULL && i < dwComponentID - 1) {
+ i++;
+ component = component->next;
+ }
+ if (component) {
+ if (*pdwBufferSize >= component->dwDataSize && *pdwNameLen >= strlenW(component->pwszName)) {
+ *pdwDataType = component->dwDataType;
+ memcpy(pvBuffer, component->lpvData, component->dwDataSize);
+ strcpyW(pwszName, component->pwszName);
+ ret = S_OK;
+ } else {
+ ret = DPNERR_BUFFERTOOSMALL;
+ }
+ *pdwBufferSize = component->dwDataSize;
+ *pdwNameLen = strlenW(component->pwszName);
+ }
+
+ TRACE("returning %x len=%d\n", ret, *pdwBufferSize);
+
+ return ret;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_GetNumComponents(PDIRECTPLAY8ADDRESS iface, PDWORD pdwNumComponents) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_AddComponent(PDIRECTPLAY8ADDRESS iface,
+ const WCHAR *const pwszName,
+ const void *const lpvData,
+ const DWORD dwDataSize,
+ const DWORD dwDataType)
+{
+ struct AddressComponent *component;
+ int found = 0;
+
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%s, %p, %d, %d)\n", iface,
+ debugstr_w(pwszName), lpvData,
+ dwDataSize, dwDataType);
+
+ if (dwDataType != GetDataType(pwszName)) {
+ TRACE("=> invalidparam\n");
+ return DPNERR_INVALIDPARAM;
+ }
+
+ component = This->component;
+ while (component) {
+ if (!strcmpW(component->pwszName, pwszName)) {
+ HeapFree(GetProcessHeap(), 0, component->pwszName);
+ HeapFree(GetProcessHeap(), 0, component->lpvData);
+ found = 1;
+ break;
+ }
+ component = component->next;
+ }
+ if (!found)
+ component = HeapAlloc(GetProcessHeap(), 0, sizeof(struct AddressComponent));
+ component->pwszName = HeapAlloc(GetProcessHeap(), 0, (strlenW(pwszName)+1) * sizeof(WCHAR));
+ component->lpvData = HeapAlloc(GetProcessHeap(), 0, dwDataSize);
+ component->dwDataSize = dwDataSize;
+ component->dwDataType = dwDataType;
+ strcpyW(component->pwszName, pwszName);
+
+ switch(dwDataType) {
+ case DPNA_DATATYPE_STRING:
+ strcpyW(component->lpvData, lpvData);
+ TRACE("string is %s\n", debugstr_w(lpvData));
+ break;
+ case DPNA_DATATYPE_DWORD:
+ TRACE("%d (%d)\n", *((const DWORD *)lpvData), dwDataSize);
+ default:
+ memcpy(component->lpvData, lpvData, dwDataSize);
+ break;
+ }
+
+ if (found) { /* we are updating an existing entry */
+ return S_OK;
+ }
+
+ component->next = NULL;
+
+ /* Put new element onto the end of the list. This is necessary so the user
+ * can call GetComponentByIndex and expect the component to be stored in
+ * the order it was added. */
+ if (This->component == NULL) {
+ This->component = component;
+ } else {
+ struct AddressComponent *temp;
+ temp = This->component;
+ while (temp->next != NULL) {
+ temp = temp->next;
+ }
+ temp->next = component;
+ }
+
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_GetComponentByName(PDIRECTPLAY8ADDRESS iface, CONST WCHAR* CONST pwszName, LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_SetDevice(PDIRECTPLAY8ADDRESS iface, const GUID *const pguidDevice)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%s)\n", iface, debugstr_guid(pguidDevice));
+ memcpy(&This->guidDevice, pguidDevice, sizeof(GUID));
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_GetComponentByIndex(PDIRECTPLAY8ADDRESS iface, CONST DWORD dwComponentID, WCHAR* pwszName,
- PDWORD pdwNameLen, void* pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Address_GetDevice(PDIRECTPLAY8ADDRESS iface, GUID *pguidDevice)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ TRACE("(%p)->(%p)\n", iface, pguidDevice);
+ if (IsEqualGUID(&This->guidDevice, &GUID_NULL)) {
+ return DPNERR_DOESNOTEXIST;
+ }
+ memcpy(pguidDevice, &This->guidDevice, sizeof(GUID));
+ return S_OK;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_AddComponent(PDIRECTPLAY8ADDRESS iface, CONST WCHAR* CONST pwszName,
- CONST void* CONST lpvData, CONST DWORD dwDataSize, CONST DWORD dwDataType) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %s, %p, %u, %x): stub\n", This, debugstr_w(pwszName), lpvData, dwDataSize, dwDataType);
-
- if (NULL == lpvData) return DPNERR_INVALIDPOINTER;
- switch (dwDataType) {
- case DPNA_DATATYPE_DWORD:
- if (sizeof(DWORD) != dwDataSize) return DPNERR_INVALIDPARAM;
- TRACE("(%p, %u): DWORD Type -> %u\n", lpvData, dwDataSize, *(const DWORD*) lpvData);
- break;
- case DPNA_DATATYPE_GUID:
- if (sizeof(GUID) != dwDataSize) return DPNERR_INVALIDPARAM;
- TRACE("(%p, %u): GUID Type -> %s\n", lpvData, dwDataSize, debugstr_guid((const GUID*) lpvData));
- break;
- case DPNA_DATATYPE_STRING:
- TRACE("(%p, %u): STRING Type -> %s\n", lpvData, dwDataSize, (const CHAR*) lpvData);
- break;
- case DPNA_DATATYPE_BINARY:
- TRACE("(%p, %u): BINARY Type\n", lpvData, dwDataSize);
- break;
- }
-
- return DPN_OK;
+HRESULT DPNET_CreateDirectPlay8Address(IUnknown *pOuter, REFIID riid, LPVOID *ppobj)
+{
+ IDirectPlay8AddressImpl *ipDP8A;
+ HRESULT hr;
+ TRACE("()\n");
+ ipDP8A = (IDirectPlay8AddressImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(IDirectPlay8AddressImpl));
+ if (ipDP8A == NULL) return E_OUTOFMEMORY;
+ ICOM_VTBL(ipDP8A) = &directPlay8AddressVT;
+ ipDP8A->lpVtbl2 = &directPlay8AddressIPVT;
+ IDirectPlay8Address_AddRef((IDirectPlay8Address *)ipDP8A);
+ ipDP8A->component = NULL;
+ ipDP8A->pvUserData = NULL;
+ ipDP8A->dwDataSize = 0;
+ ipDP8A->guidDevice = GUID_NULL;
+ ipDP8A->guidSP = GUID_NULL;
+ TRACE("Created new object: %p\n", ipDP8A);
+ hr = IDirectPlay8Address_QueryInterface((IDirectPlay8Address *)ipDP8A, riid, ppobj);
+ IDirectPlay8Address_Release((IDirectPlay8Address *)ipDP8A);
+
+ ipDP8A->hDialogMutex = CreateMutexA(NULL, FALSE, "DPNET Address DialogMutex");
+ if (SUCCEEDED(hr))
+ return S_OK;
+ else
+ return E_NOINTERFACE;
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_GetDevice(PDIRECTPLAY8ADDRESS iface, GUID* pDevGuid) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+/* DirectPlayAddressIP wrappers */
+HRESULT WINAPI DirectPlay8AddressIP_QueryInterface(PDIRECTPLAY8ADDRESSIP iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS_MULTI(IDirectPlay8AddressImpl, lpVtbl2, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ return IDirectPlay8Address_QueryInterface((PDIRECTPLAY8ADDRESS) This, riid, obj);
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_SetDevice(PDIRECTPLAY8ADDRESS iface, CONST GUID* CONST devGuid) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p, %s): stub\n", This, debugstr_guid(devGuid));
- return DPN_OK;
+ULONG WINAPI DirectPlay8AddressIP_AddRef(PDIRECTPLAY8ADDRESSIP iface)
+{
+ ICOM_THIS_MULTI(IDirectPlay8AddressImpl, lpVtbl2, iface);
+ TRACE("(%p)->()\n", iface);
+ return IDirectPlay8Address_AddRef((PDIRECTPLAY8ADDRESS) This);
}
-static HRESULT WINAPI IDirectPlay8AddressImpl_BuildFromDirectPlay4Address(PDIRECTPLAY8ADDRESS iface, LPVOID pvAddress, DWORD dwDataSize) {
- IDirectPlay8AddressImpl *This = (IDirectPlay8AddressImpl *)iface;
- TRACE("(%p): stub\n", This);
- return DPN_OK;
+ULONG WINAPI DirectPlay8AddressIP_Release(PDIRECTPLAY8ADDRESSIP iface)
+{
+ ICOM_THIS_MULTI(IDirectPlay8AddressImpl, lpVtbl2, iface);
+ TRACE("(%p)->()\n", iface);
+ return IDirectPlay8Address_Release((PDIRECTPLAY8ADDRESS) This);
}
-static const IDirectPlay8AddressVtbl DirectPlay8Address_Vtbl =
+static ICOM_VTABLE(IDirectPlay8Address) directPlay8AddressVT =
{
- IDirectPlay8AddressImpl_QueryInterface,
- IDirectPlay8AddressImpl_AddRef,
- IDirectPlay8AddressImpl_Release,
- IDirectPlay8AddressImpl_BuildFromURLW,
- IDirectPlay8AddressImpl_BuildFromURLA,
- IDirectPlay8AddressImpl_Duplicate,
- IDirectPlay8AddressImpl_SetEqual,
- IDirectPlay8AddressImpl_IsEqual,
- IDirectPlay8AddressImpl_Clear,
- IDirectPlay8AddressImpl_GetURLW,
- IDirectPlay8AddressImpl_GetURLA,
- IDirectPlay8AddressImpl_GetSP,
- IDirectPlay8AddressImpl_GetUserData,
- IDirectPlay8AddressImpl_SetSP,
- IDirectPlay8AddressImpl_SetUserData,
- IDirectPlay8AddressImpl_GetNumComponents,
- IDirectPlay8AddressImpl_GetComponentByName,
- IDirectPlay8AddressImpl_GetComponentByIndex,
- IDirectPlay8AddressImpl_AddComponent,
- IDirectPlay8AddressImpl_GetDevice,
- IDirectPlay8AddressImpl_SetDevice,
- IDirectPlay8AddressImpl_BuildFromDirectPlay4Address
+ DirectPlay8Address_QueryInterface,
+ DirectPlay8Address_AddRef,
+ DirectPlay8Address_Release,
+ DirectPlay8Address_BuildFromURLW,
+ DirectPlay8Address_BuildFromURLA,
+ DirectPlay8Address_Duplicate,
+ DirectPlay8Address_SetEqual,
+ DirectPlay8Address_IsEqual,
+ DirectPlay8Address_Clear,
+ DirectPlay8Address_GetURLW,
+ DirectPlay8Address_GetURLA,
+ DirectPlay8Address_GetSP,
+ DirectPlay8Address_GetUserData,
+ DirectPlay8Address_SetSP,
+ DirectPlay8Address_SetUserData,
+ DirectPlay8Address_GetNumComponents,
+ DirectPlay8Address_GetComponentByName,
+ DirectPlay8Address_GetComponentByIndex,
+ DirectPlay8Address_AddComponent,
+ DirectPlay8Address_GetDevice,
+ DirectPlay8Address_SetDevice,
+ (void*)0xdead7016 /* BuildFromDirectPlay4Address */
+};
+
+static ICOM_VTABLE(IDirectPlay8AddressIP) directPlay8AddressIPVT =
+{
+ DirectPlay8AddressIP_QueryInterface,
+ DirectPlay8AddressIP_AddRef,
+ DirectPlay8AddressIP_Release,
+ (void*)0xdead7024, /* BuildFromSockAddr */
+ (void*)0xdead7025, /* BuildFromAddress */
+ (void*)0xdead7026, /* BuildLocalAddress */
+ (void*)0xdead7027, /* GetSockAddress */
+ (void*)0xdead7028, /* GetLocalAddress */
+ (void*)0xdead7029 /* GetAddress */
};
-HRESULT DPNET_CreateDirectPlay8Address(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
- IDirectPlay8AddressImpl* client;
-
- TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj);
-
- client = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectPlay8AddressImpl));
- if (NULL == client) {
- *ppobj = NULL;
- return E_OUTOFMEMORY;
- }
- client->lpVtbl = &DirectPlay8Address_Vtbl;
- client->ref = 0; /* will be inited with QueryInterface */
- return IDirectPlay8AddressImpl_QueryInterface ((PDIRECTPLAY8ADDRESS)client, riid, ppobj);
-}
-
-/* returns name of given GUID */
-const char *debugstr_SP(const GUID *id) {
- static const guid_info guids[] = {
- /* CLSIDs */
- GE(CLSID_DP8SP_IPX),
- GE(CLSID_DP8SP_TCPIP),
- GE(CLSID_DP8SP_SERIAL),
- GE(CLSID_DP8SP_MODEM)
- };
- unsigned int i;
-
- if (!id) return "(null)";
-
- for (i = 0; i < sizeof(guids)/sizeof(guids[0]); i++) {
- if (IsEqualGUID(id, &guids[i].guid))
- return guids[i].name;
- }
- /* if we didn't find it, act like standard debugstr_guid */
- return debugstr_guid(id);
+/* private functions. used by the rest of dpnet.
+ * Ideally should be in an interface */
+HRESULT DPNET_Address_SetSPData(PDIRECTPLAY8ADDRESS iface, void *data,
+ spReleaseAddressInfo spReleaseCallback,
+ spDuplicateAddressInfo spDuplicateCallback)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ if (This->spData && This->spDataRelease) This->spDataRelease(This->spData);
+ This->spData = data;
+ This->spDataRelease = spReleaseCallback;
+ This->spDataDuplicate = spDuplicateCallback;
+ return S_OK;
+}
+
+HRESULT DPNET_Address_GetSPData(PDIRECTPLAY8ADDRESS iface, void **data)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ *data = This->spData;
+ return S_OK;
+}
+
+HRESULT DPNET_Address_GetDialogLock(PDIRECTPLAY8ADDRESS iface)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ if (WaitForSingleObject(This->hDialogMutex, INFINITE) != WAIT_OBJECT_0)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT DPNET_Address_ReleaseDialogLock(PDIRECTPLAY8ADDRESS iface)
+{
+ ICOM_THIS(IDirectPlay8AddressImpl, iface);
+
+ ReleaseMutex(This->hDialogMutex);
+ return S_OK;
+}
+
+/* utility functions for parsing URLs */
+
+HRESULT DPNET_GetKeyValueW(const WCHAR *url, const WCHAR *keyName,
+ WCHAR *keyValue /* [OUT] */,
+ PDWORD bufferLen /* [IN OUT] */)
+{
+ WCHAR *p, *p2, *p3;
+ DWORD requiredLen;
+
+ TRACE("%s, %p, %s, %p (%i)\n", debugstr_w(url), keyName,
+ debugstr_w(keyValue), bufferLen, *bufferLen);
+
+ p = strstrW(url, keyName);
+
+ if (p == NULL) return DPNERR_DOESNOTEXIST;
+
+ p = strchrW(p, DPNA_SEPARATOR_KEYVALUE);
+
+ if (p == NULL) return DPNERR_DOESNOTEXIST;
+ p++;
+
+ p2 = strchrW(p, DPNA_SEPARATOR_COMPONENT);
+ p3 = strchrW(p, DPNA_SEPARATOR_USERDATA);
+ if (p2 == NULL && p3 == NULL) /* end of string */
+ requiredLen = strlenW(p);
+ else if (p2 == NULL)
+ requiredLen = p3 - p;
+ else if (p3 == NULL)
+ requiredLen = p2 - p;
+ else
+ requiredLen = (p2 < p3 ? p2 : p3) - p;
+
+ if (*bufferLen < requiredLen)
+ {
+ *bufferLen = requiredLen;
+ return DPNERR_BUFFERTOOSMALL;
+ }
+ lstrcpynW(keyValue, p, requiredLen);
+ keyValue[requiredLen] = 0;
+
+ return DPN_OK;
+}
+
+static DWORD GetDataType(const WCHAR * name)
+{
+ int i;
+
+ for (i = 0; i < MAX_DPNA_TYPES; i++) {
+ if (!strcmpW(name, dpna_types[i].name)) {
+ return dpna_types[i].type;
+ }
+ }
+
+ return -1;
}
diff --git a/dlls/dpnet/client.c b/dlls/dpnet/client.c
index 89e87e6..1e0ceba 100644
--- a/dlls/dpnet/client.c
+++ b/dlls/dpnet/client.c
@@ -1,7 +1,7 @@
-/*
- * DirectPlay8 Client
- *
- * Copyright 2004 Raphael Junqueira
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -16,252 +16,106 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
*/
-#include "config.h"
-
#include <stdarg.h>
+#include <string.h>
-#define COBJMACROS
#include "windef.h"
#include "winbase.h"
-#include "wingdi.h"
#include "winuser.h"
+#include "winreg.h"
#include "objbase.h"
#include "wine/debug.h"
+#include "winerror.h"
#include "dplay8.h"
-#include "dpnet_private.h"
+#include "dplay8_private.h"
-WINE_DEFAULT_DEBUG_CHANNEL(dpnet);
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
-/* IDirectPlay8Client IUnknown parts follow: */
-static HRESULT WINAPI IDirectPlay8ClientImpl_QueryInterface(PDIRECTPLAY8CLIENT iface, REFIID riid, LPVOID *ppobj)
-{
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
+static ICOM_VTABLE(IDirectPlay8Client) directPlay8ClientVT;
- if (IsEqualGUID(riid, &IID_IUnknown)
- || IsEqualGUID(riid, &IID_IDirectPlay8Client)) {
- IUnknown_AddRef(iface);
- *ppobj = This;
- return DPN_OK;
+HRESULT WINAPI DirectPlay8Client_QueryInterface(PDIRECTPLAY8CLIENT iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS(IDirectPlay8ClientImpl, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDirectPlay8Client, riid))
+ {
+ This->ref++;
+ *obj = This;
+ return S_OK;
}
-
- WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI IDirectPlay8ClientImpl_AddRef(PDIRECTPLAY8CLIENT iface) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- ULONG refCount = InterlockedIncrement(&This->ref);
-
- TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
-
- return refCount;
-}
-
-static ULONG WINAPI IDirectPlay8ClientImpl_Release(PDIRECTPLAY8CLIENT iface) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- ULONG refCount = InterlockedDecrement(&This->ref);
-
- TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
-
- if (!refCount) {
- HeapFree(GetProcessHeap(), 0, This);
+ else
+ {
+ FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj);
+ return E_NOINTERFACE;
}
- return refCount;
-}
-
-/* IDirectPlay8Client Interface follow: */
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_Initialize(PDIRECTPLAY8CLIENT iface, PVOID CONST pvUserContext, CONST PFNDPNMESSAGEHANDLER pfn, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%p,%p,%x): Stub\n", This, pvUserContext, pfn, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_EnumServiceProviders(PDIRECTPLAY8CLIENT iface,
- CONST GUID * CONST pguidServiceProvider,
- CONST GUID * CONST pguidApplication,
- DPN_SERVICE_PROVIDER_INFO * CONST pSPInfoBuffer,
- PDWORD CONST pcbEnumData,
- PDWORD CONST pcReturned,
- CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_EnumHosts(PDIRECTPLAY8CLIENT iface,
- PDPN_APPLICATION_DESC CONST pApplicationDesc,
- IDirectPlay8Address * CONST pAddrHost,
- IDirectPlay8Address * CONST pDeviceInfo,
- PVOID CONST pUserEnumData, CONST DWORD dwUserEnumDataSize, CONST DWORD dwEnumCount,
- CONST DWORD dwRetryInterval,
- CONST DWORD dwTimeOut,
- PVOID CONST pvUserContext,
- DPNHANDLE * CONST pAsyncHandle,
- CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- /*FIXME("(%p):(%p,%p,%p,%p,%lu,%lu,%lu,%lu): Stub\n", This, pApplicationDesc, pAddrHost, pDeviceInfo, pUserEnumData, dwUserEnumDataSize, dwEnumCount, dwRetryInterval, dwTimeOut);*/
- FIXME("(%p):(%p,%p,%x): Stub\n", This, pvUserContext, pAsyncHandle, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_CancelAsyncOperation(PDIRECTPLAY8CLIENT iface, CONST DPNHANDLE hAsyncHandle, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%u,%x): Stub\n", This, hAsyncHandle, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_Connect(PDIRECTPLAY8CLIENT iface,
- CONST DPN_APPLICATION_DESC * CONST pdnAppDesc,
- IDirectPlay8Address * CONST pHostAddr,
- IDirectPlay8Address * CONST pDeviceInfo,
- CONST DPN_SECURITY_DESC * CONST pdnSecurity,
- CONST DPN_SECURITY_CREDENTIALS * CONST pdnCredentials,
- CONST void * CONST pvUserConnectData,
- CONST DWORD dwUserConnectDataSize,
- void * CONST pvAsyncContext,
- DPNHANDLE * CONST phAsyncHandle,
- CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%p,%p,%x): Stub\n", This, pvAsyncContext, phAsyncHandle, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_Send(PDIRECTPLAY8CLIENT iface,
- CONST DPN_BUFFER_DESC * CONST prgBufferDesc,
- CONST DWORD cBufferDesc,
- CONST DWORD dwTimeOut,
- void * CONST pvAsyncContext,
- DPNHANDLE * CONST phAsyncHandle,
- CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%p,%p,%x): Stub\n", This, pvAsyncContext, phAsyncHandle, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_GetSendQueueInfo(PDIRECTPLAY8CLIENT iface, DWORD * CONST pdwNumMsgs, DWORD * CONST pdwNumBytes, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_GetApplicationDesc(PDIRECTPLAY8CLIENT iface, DPN_APPLICATION_DESC * CONST pAppDescBuffer, DWORD * CONST pcbDataSize, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_SetClientInfo(PDIRECTPLAY8CLIENT iface,
- CONST DPN_PLAYER_INFO * CONST pdpnPlayerInfo,
- PVOID CONST pvAsyncContext,
- DPNHANDLE * CONST phAsyncHandle,
- CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%p,%p,%x): Stub\n", This, pvAsyncContext, phAsyncHandle, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_GetServerInfo(PDIRECTPLAY8CLIENT iface, DPN_PLAYER_INFO * CONST pdpnPlayerInfo, DWORD * CONST pdwSize, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_GetServerAddress(PDIRECTPLAY8CLIENT iface, IDirectPlay8Address ** CONST pAddress, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_Close(PDIRECTPLAY8CLIENT iface, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
}
-static HRESULT WINAPI IDirectPlay8ClientImpl_ReturnBuffer(PDIRECTPLAY8CLIENT iface, CONST DPNHANDLE hBufferHandle, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_GetCaps(PDIRECTPLAY8CLIENT iface, DPN_CAPS * CONST pdpCaps, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_SetCaps(PDIRECTPLAY8CLIENT iface, CONST DPN_CAPS * CONST pdpCaps, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
-
-static HRESULT WINAPI IDirectPlay8ClientImpl_SetSPCaps(PDIRECTPLAY8CLIENT iface, CONST GUID * CONST pguidSP, CONST DPN_SP_CAPS * CONST pdpspCaps, CONST DWORD dwFlags ) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
+ULONG WINAPI DirectPlay8Client_AddRef(PDIRECTPLAY8CLIENT iface)
+{
+ ICOM_THIS(IDirectPlay8ClientImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ return ++This->ref;
}
-static HRESULT WINAPI IDirectPlay8ClientImpl_GetSPCaps(PDIRECTPLAY8CLIENT iface, CONST GUID * CONST pguidSP, DPN_SP_CAPS * CONST pdpspCaps, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
+ULONG WINAPI DirectPlay8Client_Release(PDIRECTPLAY8CLIENT iface)
+{
+ ICOM_THIS(IDirectPlay8ClientImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ if (--This->ref) return This->ref;
-static HRESULT WINAPI IDirectPlay8ClientImpl_GetConnectionInfo(PDIRECTPLAY8CLIENT iface, DPN_CONNECTION_INFO * CONST pdpConnectionInfo, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
-}
+ FIXME("destroy this and everything\n");
-static HRESULT WINAPI IDirectPlay8ClientImpl_RegisterLobby(PDIRECTPLAY8CLIENT iface, CONST DPNHANDLE dpnHandle, struct IDirectPlay8LobbiedApplication * CONST pIDP8LobbiedApplication, CONST DWORD dwFlags) {
- IDirectPlay8ClientImpl *This = (IDirectPlay8ClientImpl *)iface;
- FIXME("(%p):(%x): Stub\n", This, dwFlags);
- return DPN_OK;
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
}
-static const IDirectPlay8ClientVtbl DirectPlay8Client_Vtbl =
+HRESULT DPNET_CreateDirectPlay8Client(IUnknown *pOuter, REFIID riid, LPVOID *ppobj)
{
- IDirectPlay8ClientImpl_QueryInterface,
- IDirectPlay8ClientImpl_AddRef,
- IDirectPlay8ClientImpl_Release,
- IDirectPlay8ClientImpl_Initialize,
- IDirectPlay8ClientImpl_EnumServiceProviders,
- IDirectPlay8ClientImpl_EnumHosts,
- IDirectPlay8ClientImpl_CancelAsyncOperation,
- IDirectPlay8ClientImpl_Connect,
- IDirectPlay8ClientImpl_Send,
- IDirectPlay8ClientImpl_GetSendQueueInfo,
- IDirectPlay8ClientImpl_GetApplicationDesc,
- IDirectPlay8ClientImpl_SetClientInfo,
- IDirectPlay8ClientImpl_GetServerInfo,
- IDirectPlay8ClientImpl_GetServerAddress,
- IDirectPlay8ClientImpl_Close,
- IDirectPlay8ClientImpl_ReturnBuffer,
- IDirectPlay8ClientImpl_GetCaps,
- IDirectPlay8ClientImpl_SetCaps,
- IDirectPlay8ClientImpl_SetSPCaps,
- IDirectPlay8ClientImpl_GetSPCaps,
- IDirectPlay8ClientImpl_GetConnectionInfo,
- IDirectPlay8ClientImpl_RegisterLobby
+ IDirectPlay8ClientImpl *ipDP8C;
+ HRESULT hr;
+ TRACE("()\n");
+ ipDP8C = (IDirectPlay8ClientImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(IDirectPlay8ClientImpl));
+ if (ipDP8C == NULL) return E_OUTOFMEMORY;
+ ICOM_VTBL(ipDP8C) = &directPlay8ClientVT;
+ IDirectPlay8Client_AddRef((IDirectPlay8Client *)ipDP8C);
+ TRACE("Created new interface: %p\n", ipDP8C);
+ hr = IDirectPlay8Client_QueryInterface((IDirectPlay8Client *)ipDP8C, riid, ppobj);
+ IDirectPlay8Client_Release((IDirectPlay8Client *)ipDP8C);
+ if (SUCCEEDED(hr))
+ return S_OK;
+ else
+ return E_NOINTERFACE;
+}
+
+static ICOM_VTABLE(IDirectPlay8Client) directPlay8ClientVT =
+{
+ DirectPlay8Client_QueryInterface,
+ DirectPlay8Client_AddRef,
+ DirectPlay8Client_Release,
+ (void*)0xdead3004, /* Initilize */
+ (void*)0xdead3005, /* EnumServiceProviers */
+ (void*)0xdead3006, /* EnumHosts */
+ (void*)0xdead3007, /* CancelAsyncOperation */
+ (void*)0xdead3008, /* Connect */
+ (void*)0xdead3009, /* Send */
+ (void*)0xdead300a, /* GetSendQueueInfo */
+ (void*)0xdead300b, /* GetApplicationDesc */
+ (void*)0xdead300c, /* SetClientInfo */
+ (void*)0xdead300d, /* GetServerInfo */
+ (void*)0xdead300e, /* GetServerAddress */
+ (void*)0xdead300f, /* Close */
+ (void*)0xdead3010, /* ReturnBuffer */
+ (void*)0xdead3011, /* GetCaps */
+ (void*)0xdead3012, /* SetCaps */
+ (void*)0xdead3013, /* SetSPCaps */
+ (void*)0xdead3014, /* GetSPCaps */
+ (void*)0xdead3015, /* GetConnectionInfo */
+ (void*)0xdead3016 /* RegisterLobby */
};
-HRESULT DPNET_CreateDirectPlay8Client(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
- IDirectPlay8ClientImpl* client;
-
- TRACE("(%p, %s, %p)\n", punkOuter, debugstr_guid(riid), ppobj);
-
- client = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectPlay8ClientImpl));
- if (NULL == client) {
- *ppobj = NULL;
- return E_OUTOFMEMORY;
- }
- client->lpVtbl = &DirectPlay8Client_Vtbl;
- client->ref = 0; /* will be inited with QueryInterface */
- return IDirectPlay8ClientImpl_QueryInterface ((PDIRECTPLAY8CLIENT)client, riid, ppobj);
-}
diff --git a/dlls/dpnet/debug.c b/dlls/dpnet/debug.c
new file mode 100644
index 0000000..1a8ca78
--- /dev/null
+++ b/dlls/dpnet/debug.c
@@ -0,0 +1,57 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "wine/debug.h"
+
+#include <ctype.h>
+
+void debug_hexdump(void *data, unsigned long len)
+{
+ unsigned int i;
+ char *cdata = (char *)data;
+ char textout[16];
+
+ for (i = 0; i < len; i++)
+ {
+ if ((i % 8) == 0 && i) DPRINTF(" ");
+ if ((i % 16) == 0 && i) DPRINTF(" '%.8s' '%.8s'\n", &textout[0], &textout[8]);
+ textout[i % 16] = (cdata[i] && isprint(cdata[i])) ? cdata[i] : '.';
+ DPRINTF("%02hhx ", cdata[i]);
+ }
+ if (i % 16)
+ {
+ unsigned int j;
+ for (j = 0; j < (16 - (i % 16)); j++)
+ {
+ if (((16 - (i % 16)) - j) == 8) DPRINTF(" ");
+ DPRINTF(".. ");
+ }
+ DPRINTF(" '");
+ for (j = 0; j < (i % 16); j++)
+ {
+ DPRINTF("%c", textout[j]);
+ if (j == 8) DPRINTF("' '");
+ }
+ DPRINTF("'\n");
+ }
+ DPRINTF("\n");
+
+}
+
diff --git a/dlls/dpnet/dialog.c b/dlls/dpnet/dialog.c
new file mode 100644
index 0000000..ae37ae2
--- /dev/null
+++ b/dlls/dpnet/dialog.c
@@ -0,0 +1,113 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "winuser.h"
+
+#include "dplay8.h"
+#include "dpaddr.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+WCHAR *pHostNameUserInput = NULL;
+HANDLE hHostNameUserInputMutex;
+HINSTANCE hinstDpnet;
+
+HRESULT DPNET_HostNameDialogInit(HINSTANCE hinstDLL)
+{
+ pHostNameUserInput = NULL;
+ hinstDpnet = hinstDLL;
+ hHostNameUserInputMutex = CreateMutexA(NULL, FALSE, "DPNET HostNameUserInputMutex");
+ return TRUE;
+}
+
+HRESULT DPNET_HostNameDialogUninit()
+{
+ CloseHandle(hHostNameUserInputMutex);
+ return TRUE;
+}
+
+BOOL WINAPI DPNET_HostNameDlgProc(HWND hwnd, UINT msg, WPARAM wParam,
+ LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_COMMAND:
+ switch LOWORD(wParam)
+ {
+ case IDOK:
+ {
+ int textlen;
+ textlen = GetWindowTextLengthW(GetDlgItem(hwnd, 701)) + 1;
+ pHostNameUserInput = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * textlen);
+ GetWindowTextW(GetDlgItem(hwnd, 701), pHostNameUserInput,
+ textlen);
+ EndDialog(hwnd, wParam);
+ return TRUE;
+ }
+ case IDCANCEL:
+ EndDialog(hwnd, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* FIXME: maybe we should return a DirectPlay8Address ? */
+HRESULT DPNET_HostNameShowDialog(PWCHAR *ppUserInput)
+{
+ int hostnamebytelen;
+ HINSTANCE hinstDpnet2 = LoadLibraryA("DPNET");
+
+ TRACE("(%p)\n", ppUserInput);
+
+ WaitForSingleObject(hHostNameUserInputMutex, INFINITE);
+ DialogBoxA(hinstDpnet2, "HOSTNAME", 0, DPNET_HostNameDlgProc);
+
+ if (!pHostNameUserInput && !lstrlenW(pHostNameUserInput))
+ {
+ TRACE("returning fail\n");
+ return E_FAIL;
+ }
+ hostnamebytelen = (lstrlenW(pHostNameUserInput)+1) * sizeof(WCHAR);
+ *ppUserInput = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, hostnamebytelen);
+ memcpy(*ppUserInput, pHostNameUserInput, hostnamebytelen);
+ HeapFree(GetProcessHeap(), 0, pHostNameUserInput);
+
+ ReleaseMutex(hHostNameUserInputMutex);
+ return S_OK;
+}
+
+HRESULT DPNET_HostNameFree(PWCHAR pUserInput)
+{
+ HeapFree(GetProcessHeap(), 0, pUserInput);
+ return S_OK;
+}
+
diff --git a/dlls/dpnet/dplay8_private.h b/dlls/dpnet/dplay8_private.h
new file mode 100644
index 0000000..d6b3785
--- /dev/null
+++ b/dlls/dpnet/dplay8_private.h
@@ -0,0 +1,453 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_DPLAY8_PRIVATE_H
+#define __WINE_DPLAY8_PRIVATE_H
+
+#include "dplay8.h"
+#include "dplobby8.h"
+#include "dplay8sp.h"
+
+#include "winsock2.h"
+
+#define ICOM_THIS(impl,iface) impl* const This=(impl*)(iface)
+#define ICOM_VTABLE(iface) iface##Vtbl
+#define ICOM_VFIELD(iface) ICOM_VTABLE(iface)* lpVtbl
+#define ICOM_VTBL(iface) (iface)->lpVtbl
+#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
+
+
+typedef struct IDirectPlay8ClientImpl IDirectPlay8ClientImpl;
+typedef struct IDirectPlay8PeerImpl IDirectPlay8PeerImpl;
+typedef struct IDirectPlay8ServerImpl IDirectPlay8ServerImpl;
+typedef struct IDirectPlay8LobbiedApplicationImpl IDirectPlay8LobbiedApplicationImpl;
+typedef struct IDirectPlay8LobbyClientImpl IDirectPlay8LobbyClientImpl;
+typedef struct IDirectPlay8AddressImpl IDirectPlay8AddressImpl;
+
+typedef struct IDirectPlay8ThreadPoolImpl IDirectPlay8ThreadPoolImpl;
+typedef struct IDirectPlay8SP_TCPImpl IDirectPlay8SP_TCPImpl;
+typedef struct IDirectPlay8SP_TCPIPImpl IDirectPlay8SP_TCPIPImpl;
+
+typedef struct tpJobQueueNode tpJobQueueNode;
+typedef struct dpOutMessageToAddr dpOutMessageToAddr;
+
+typedef struct DPNET_AsyncOp DPNET_AsyncOp;
+
+/* FIXME: add some "pre-send", "retry", "timeout", "complete",
+ * etc, callbacks to this structure. Also we'll need a way
+ * to handle multiple destinations. */
+
+struct DPNET_AsyncOp {
+ DPNET_AsyncOp *prev, *next;
+ DWORD dwType, dwFlags, dwID;
+ PVOID pvUserContext;
+ HANDLE hSyncEvent;
+ BOOL forget;
+
+ IDirectPlay8Address *pAddrHost;
+ IDirectPlay8Address *pAddrDev;
+ DWORD dwRetryLimit, dwRetryInterval, dwTimeOut;
+ DWORD dwTimeSent;
+ DWORD cUserBuffer;
+ DPN_BUFFER_DESC PackBuffer;
+ DPN_BUFFER_DESC UserBuffer[8];
+};
+
+typedef struct dpPlayer dpPlayer;
+
+typedef enum {
+ PLAYER_UNKNOWN,
+ PLAYER_REQUEST_SENT,
+ PLAYER_RESPONSE_SENT,
+ PLAYER_CONNECTED,
+ PLAYER_ACCEPTED,
+ PLAYER_REJECTED,
+ PLAYER_ACTIVE,
+} PlayerStatus;
+
+struct dpPlayer
+{
+ dpPlayer *prev; /* only for remote players */
+ dpPlayer *next; /* ditto */
+
+ BOOL set;
+ PlayerStatus status;
+ PVOID pvPlayerContext;
+
+ DPNID dwPlayerID;
+ IDirectPlay8Address *pAddress;
+ DWORD conn_id;
+ DWORD ver;
+ DWORD dplay_ver;
+
+ LPWSTR name;
+ PVOID data;
+ DWORD data_len;
+
+ BYTE next_in, next_out, ack_in, ack_out;
+
+ /* hopefully one critical section per player is OK */
+ CRITICAL_SECTION cs;
+
+ PVOID conn_data;
+ DWORD conn_data_len;
+ PVOID conn_data_ctx;
+
+ PVOID reply_data;
+ DWORD reply_data_len;
+};
+
+struct DirectPlay8GlobalData
+{
+ PFNDPNMESSAGEHANDLER pfMessageHandler;
+ PVOID pvUserContext;
+
+ dpOutMessageToAddr *msgToAddrTail;
+ DPN_CAPS dpnCaps;
+
+ /* current service provider list */
+ DPN_SERVICE_PROVIDER_INFO *pSPAvailable;
+ DWORD SPAvailableCount;
+
+ /* selected service provider */
+ GUID guidSP;
+ IDirectPlay8ServiceProvider *sp;
+
+ BYTE dwPacketCount;
+
+ dpPlayer localPlayer;
+ dpPlayer *remotePlayers;
+ dpPlayer *remoteHost;
+ CRITICAL_SECTION cs_player;
+
+ DPN_APPLICATION_DESC appdesc;
+
+ BOOL is_host;
+ LONG pkt_id;
+ LONG player_id;
+
+ CRITICAL_SECTION cs_aop;
+ DPNET_AsyncOp *aop_head;
+ DPNET_AsyncOp *aop_tail;
+};
+
+struct IDirectPlay8ClientImpl
+{
+ /* IUnknown fields */
+ const IDirectPlay8ClientVtbl *lpVtbl;
+ DWORD ref;
+ /* IDirectPlay8Client fields */
+ void *dummy;
+};
+
+struct IDirectPlay8PeerImpl
+{
+ /* IUnknown fields */
+ const IDirectPlay8PeerVtbl *lpVtbl;
+ DWORD ref;
+ /* IDirectPlay8Peer fields */
+ BOOL connected;
+ IDirectPlay8Address *pHostAddr;
+ DirectPlay8GlobalData dp8gdData;
+};
+
+struct IDirectPlay8ServerImpl
+{
+ /* IUnknown fields */
+ const IDirectPlay8ServerVtbl *lpVtbl;
+ DWORD ref;
+ /* IDirectPlay8Server fields */
+ void *dummy;
+};
+
+struct IDirectPlay8LobbiedApplicationImpl
+{
+ /* IUnknown fields */
+ const IDirectPlay8LobbiedApplicationVtbl *lpVtbl;
+ DWORD ref;
+ /* IDirectPlay8LobbiedApplicationImpl fields */
+ void *dummy;
+};
+
+struct IDirectPlay8LobbyClientImpl
+{
+ /* IUnknown fields */
+ const IDirectPlay8LobbyClientVtbl *lpVtbl;
+ DWORD ref;
+ /* IDirectPlay8LobbyClientImpl fields */
+ void *dummy;
+};
+
+struct AddressComponent
+{
+ WCHAR *pwszName;
+ void *lpvData;
+ DWORD dwDataSize;
+ DWORD dwDataType;
+ struct AddressComponent *next;
+};
+
+/* a bit hacky. should be in some interface */
+typedef void (*spReleaseAddressInfo)(PVOID);
+/* shouldn't need to duplicate !!!! SHOULD USE URL. HACK */
+typedef void (*spDuplicateAddressInfo)(IDirectPlay8Address *, PVOID);
+
+struct IDirectPlay8AddressImpl
+{
+ /* IUnknown fields */
+ const IDirectPlay8AddressVtbl *lpVtbl;
+ const IDirectPlay8AddressIPVtbl *lpVtbl2;
+ DWORD ref;
+ /* IDriectPlay8Address / IDirectPlay8AddressIP fields */
+ GUID guidSP;
+ GUID guidDevice;
+
+ struct AddressComponent *component;
+ void *pvUserData;
+ DWORD dwDataSize;
+
+ HANDLE hDialogMutex; /* HACK: if we are sending to this address and the
+ * service provider wants to show a dialogbox, it needs to
+ * lock this - ensures that we don't show multiple dialog boxs
+ * at once etc.
+ * This can go once sending is windowed and in a single thread.
+ */
+ spReleaseAddressInfo spDataRelease;
+ spDuplicateAddressInfo spDataDuplicate;
+ void *spData;
+};
+
+typedef struct tpReadNode tpReadNode;
+
+typedef BOOL (*tpInitFunc)(void *, tpReadNode *);
+typedef BOOL (*tpReadFunc)(void *, tpReadNode *);
+
+struct tpReadNode {
+ tpReadNode *prev;
+ tpReadNode *next;
+
+ LPVOID ctx;
+ tpInitFunc pfnInit;
+ tpReadFunc pfnRead;
+ OVERLAPPED ovl;
+ DPN_BUFFER_DESC Addr;
+ DPN_BUFFER_DESC Data;
+ IDirectPlay8Address *pAddr;
+};
+
+typedef struct tpWriteNode tpWriteNode;
+
+typedef BOOL (*tpWriteFunc)(void *, tpWriteNode *);
+typedef BOOL (*tpTimeFunc)(void *, tpWriteNode *);
+
+struct tpWriteNode {
+ tpWriteNode *prev;
+ tpWriteNode *next;
+
+ LPVOID ctx;
+ tpWriteFunc pfnWrite;
+ tpTimeFunc pfnTime;
+ DPNET_AsyncOp *aop;
+};
+
+typedef struct tpThreadNode tpThreadNode;
+
+struct tpThreadNode {
+ tpThreadNode *prev;
+ tpThreadNode *next;
+
+ HANDLE hThread, hJob;
+ DWORD dwID;
+
+ CRITICAL_SECTION cs;
+ BOOL die_please;
+ tpReadNode *Read;
+};
+
+struct IDirectPlay8ThreadPoolImpl
+{
+ /* IUnknown fields */
+ const IDirectPlay8ThreadPoolVtbl *lpVtbl;
+ DWORD ref;
+
+ /* IDirectPlay8ThreadPool fields */
+ PVOID pvUserContext;
+ PFNDPNMESSAGEHANDLER pfn;
+ DWORD dwNumThreads, dwCurThreads;
+ CRITICAL_SECTION cs_thread;
+ tpThreadNode *threads;
+
+ HANDLE hTimer;
+ LARGE_INTEGER liDueTime;
+ CRITICAL_SECTION cs_timer;
+};
+
+struct IDirectPlay8SP_TCPIPImpl
+{
+ /* IUnknown fields */
+ const IDirectPlay8ServiceProviderVtbl *lpVtbl;
+ DWORD ref;
+ /* IDirectPlay8SPWinsockTCPIP fields */
+ SOCKET socket;
+ DWORD dwMaxSize;
+ IDirectPlay8ThreadPool *threadPool;
+ DirectPlay8GlobalData *dp8gdData;
+ spMessageReceived msgCallback;
+ DPN_SP_CAPS dpnSPCaps;
+};
+
+/* client.c */
+HRESULT DPNET_CreateDirectPlay8Client(IUnknown *pOuter, REFIID riid, LPVOID *ppobj);
+
+/* peer.c */
+HRESULT DPNET_CreateDirectPlay8Peer(IUnknown *pOuter, REFIID riid, LPVOID *ppobj);
+
+/* server.c */
+HRESULT DPNET_CreateDirectPlay8Server(IUnknown *pOuter, REFIID riid, LPVOID *ppobj);
+
+/* lobbiedapp.c */
+HRESULT DPNET_CreateDirectPlay8LobbiedApplication(IUnknown *pOuter, REFIID riid, LPVOID *ppobj);
+
+/* lobbyclient.c */
+HRESULT DPNET_CreateDirectPlay8LobbyClient(IUnknown *pOuter, REFIID riid, LPVOID *ppobj);
+
+/* address.c */
+HRESULT DPNET_CreateDirectPlay8Address(IUnknown *pOuter, REFIID riid, LPVOID *ppobj);
+HRESULT DPNET_Address_SetSPData(PDIRECTPLAY8ADDRESS iface, void *data,
+ spReleaseAddressInfo spReleaseCallback,
+ spDuplicateAddressInfo spDuplicateCallback);
+HRESULT DPNET_Address_GetSPData(PDIRECTPLAY8ADDRESS iface, void **data);
+HRESULT DPNET_Address_GetDialogLock(PDIRECTPLAY8ADDRESS iface);
+HRESULT DPNET_Address_ReleaseDialogLock(PDIRECTPLAY8ADDRESS iface);
+
+HRESULT DPNET_GetKeyValueW(const WCHAR *url, const WCHAR *keyName,
+ WCHAR *keyValue /* [OUT] */,
+ PDWORD bufferLen /* [IN OUT] */);
+
+/* sp_tcpip.c */
+HRESULT DPNET_CreateDirectPlay8SP_TCPIP(IUnknown *pOuter, REFIID riid, LPVOID *ppobj);
+
+/* threadpool.c */
+HRESULT DPNET_CreateDirectPlay8ThreadPool(IUnknown *pOuter, REFIID riid, LPVOID *ppobj);
+HRESULT DPNET_GetThreadPool(IDirectPlay8ThreadPool **ppThreadPool, DWORD dwNumThreads);
+void DPNET_InitAsyncRead(IDirectPlay8ThreadPool *pThreadPool, tpInitFunc pfnInit, tpReadFunc pfnRead, void *data);
+
+/* general.c */
+WCHAR *DPNET_strndupW(WCHAR *pwszSource, int len);
+WCHAR *DPNET_strdupW(WCHAR *pwszSource);
+DPNET_AsyncOp* DPNET_AsyncAlloc(DirectPlay8GlobalData *dp8gdData, DWORD dwType, DWORD dwSize);
+HRESULT DPNET_AsyncFree(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop);
+void DPNET_AsyncSetSync(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop);
+void DPNET_AsyncSignal(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop);
+void DPNET_AsyncWait(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop);
+void DPNET_AsyncInsert(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop);
+void DPNET_AsyncRemove(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop);
+DPNET_AsyncOp* DPNET_AsyncSearch(DirectPlay8GlobalData *dp8gdData, DWORD dwType, DWORD dwID);
+HRESULT DPNET_ObjInit(DirectPlay8GlobalData *dp8gdData, PVOID const pvUserContext,
+ const PFNDPNMESSAGEHANDLER pfn, const DWORD dwFlags);
+void DPNET_ObjFree(DirectPlay8GlobalData *dp8gdData);
+DWORD DPNET_Random(DirectPlay8GlobalData *dp8gdData);
+HRESULT DPNET_EnumServiceProviders(DirectPlay8GlobalData *dp8gdData,
+ const GUID *const pguidServiceProvider,
+ const GUID *const pguidApplication,
+ DPN_SERVICE_PROVIDER_INFO *pSPInfoBuffer,
+ DWORD *pcbEnumData,
+ DWORD *pcReturned,
+ DWORD dwFlags);
+
+/* session.c */
+void DPNET_KillPlayers(DirectPlay8GlobalData *dp8gdData);
+HRESULT DPNET_GetCaps(DirectPlay8GlobalData *dp8gdData,
+ DPN_CAPS *const pdpCaps,
+ const DWORD dwFlags);
+HRESULT DPNET_GetSPCaps(DirectPlay8GlobalData *dp8gdData,
+ const GUID *const pguidSP,
+ DPN_SP_CAPS *const pdpnSPCaps,
+ const DWORD dwFlags);
+HRESULT DPNET_CancelAsyncOperation(DirectPlay8GlobalData *dp8gdData,
+ const DPNHANDLE hAsyncHandle,
+ const DWORD dwFlags);
+HRESULT DPNET_ReturnBuffer(DirectPlay8GlobalData *dp8gdData,
+ const DPNHANDLE hBufferHandle,
+ const DWORD dwFlags);
+HRESULT DPNET_GetApplicationDesc(DirectPlay8GlobalData *dp8gdData,
+ DPN_APPLICATION_DESC *const pAppDescBuffer,
+ DWORD *const pcbDataSize,
+ const DWORD dwFlags);
+HRESULT DPNET_SetPeerInfo(DirectPlay8GlobalData *dp8gdData,
+ const DPN_PLAYER_INFO *const pdpnPlayerInfo,
+ PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle,
+ const DWORD dwFlags);
+HRESULT DPNET_GetPeerInfo(DirectPlay8GlobalData *dp8gdData,
+ const DPNID dpnid,
+ DPN_PLAYER_INFO *const pdpnPlayerInfo,
+ DWORD *const pdwSize,
+ const DWORD dwFlags);
+HRESULT DPNET_GetPlayerContext(DirectPlay8GlobalData *dp8gdData,
+ const DPNID dpnid,
+ PVOID *const ppvPlayerContext,
+ const DWORD dwFlags);
+HRESULT DPNET_EnumHosts(DirectPlay8GlobalData *dp8gdData,
+ PDPN_APPLICATION_DESC const pApplicationDesc,
+ IDirectPlay8Address *const pAddrHost, IDirectPlay8Address *const pDeviceInfo,
+ PVOID const pUserEnumData, const DWORD dwUserEnumDataSize,
+ const DWORD dwEnumCount, const DWORD dwRetryInterval,
+ const DWORD dwTimeOut, PVOID const pvUserContext, DPNHANDLE *const pAsyncHandle,
+ const DWORD dwFlags);
+HRESULT DPNET_Connect(DirectPlay8GlobalData *dp8gdData,
+ const DPN_APPLICATION_DESC *const pdnAppDesc,
+ IDirectPlay8Address *pAddrHost,
+ IDirectPlay8Address *pDeviceInfo,
+ const DPN_SECURITY_DESC * const pdnSecurity,
+ const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
+ const void *const pvUserConnectData,
+ DWORD dwUserConnectDataSize,
+ void *pvPlayerContext, void *pvAsyncContext,
+ DPNHANDLE *phAsyncHandle, DWORD dwFlags);
+HRESULT DPNET_Host(DirectPlay8GlobalData *dp8gdData,
+ const DPN_APPLICATION_DESC *const pdnAppDesc,
+ IDirectPlay8Address **const prgpDeviceInfo,
+ const DWORD cDeviceInfo,
+ const DPN_SECURITY_DESC *const pdnSecurity,
+ const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
+ void *pvPlayerContext,
+ const DWORD dwFlags);
+HRESULT DPNET_SendTo(DirectPlay8GlobalData *dp8gdData, const DPNID dpnid,
+ const DPN_BUFFER_DESC *const pBufferDesc, const DWORD cBufferDesc,
+ const DWORD dwTimeOut, void *pvAsyncContext,
+ DPNHANDLE *const phAsyncHandle, const DWORD dwFlags);
+
+/* dialog.c */
+HRESULT DPNET_HostNameDialogInit(HINSTANCE hinstDLL);
+HRESULT DPNET_HostNameDialogUninit();
+HRESULT DPNET_HostNameShowDialog(PWCHAR *ppUserInput);
+HRESULT DPNET_HostNameFree(PWCHAR pUserInput);
+
+
+/* debug.c */
+void debug_hexdump(void *data, unsigned long len);
+
+/* parse.c */
+void DPNET_StartParse(void);
+void DPNET_StopParse(void);
+void DPNET_ParsePacket(int proto, struct sockaddr_in *from, struct sockaddr_in *to,
+ const DPN_BUFFER_DESC *buf, const DWORD bufs);
+
+#endif
diff --git a/dlls/dpnet/dplay8sp.h b/dlls/dpnet/dplay8sp.h
new file mode 100644
index 0000000..f4c1c4c
--- /dev/null
+++ b/dlls/dpnet/dplay8sp.h
@@ -0,0 +1,107 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* This is the header file for the service providers
+ * PLEASE NOTE: The dp8 service provider API is NOT available from Microsoft
+ * and they are not willing to give it to anyone. So this interface has been
+ * created by David Hammerton (TransGaming Technologies). So feel
+ * free to change it if you want.
+ * It is very much a work in progress!
+ */
+
+#ifndef _WINE_DPLAY8SP_H__
+#define _WINE_DPLAY8SP_H__
+
+#include "ole2.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "dplay8.h"
+
+/* IID for DirectPlay8 Service Providers */
+/* {985E2C76-66BC-4d66-AD8E-ED3801F1B459} */
+DEFINE_GUID(IID_IDirectPlay8ServiceProvider,
+0x985e2c76, 0x66bc, 0x4d66, 0xad, 0x8e, 0xed, 0x38, 0x1, 0xf1, 0xb4, 0x59);
+
+/* interface pointers */
+typedef struct IDirectPlay8ServiceProvider *PDIRECTPLAY8SERVICEPROVIDER;
+
+/* external types */
+typedef struct DirectPlay8GlobalData DirectPlay8GlobalData;
+
+/* callback functions */
+typedef BOOL (*spMessageReceived)(DirectPlay8GlobalData *, void *, int, IDirectPlay8Address *);
+
+/* non structure/message datatypes */
+
+/* message identifiers */
+
+/* constants */
+
+/* Flags */
+
+/* non message structures */
+
+/* message callback structures */
+
+/* functions */
+
+/******** Interfaces *******/
+
+/* IDirectPlay8ServiceProvider */
+#define INTERFACE IDirectPlay8ServiceProvider
+DECLARE_INTERFACE_(IDirectPlay8ServiceProvider,IUnknown)
+{
+ /*** IUnknown methods ***/
+ STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
+ STDMETHOD_(ULONG,AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG,Release)(THIS) PURE;
+ /*** IDirectPlay8ServiceProvider methods ***/
+ STDMETHOD_(HRESULT,Initialize)(THIS_ DirectPlay8GlobalData * dp8gdData, spMessageReceived msgCallback, DWORD dwFlags) PURE;
+ STDMETHOD_(HRESULT,SendTo)(THIS_ IDirectPlay8Address * pAddrDest, const DPN_BUFFER_DESC * prgBufferDesc, const DWORD cBufferDesc, DWORD dwFlags) PURE;
+ STDMETHOD_(HRESULT,SetSPCaps)(THIS_ DPN_SP_CAPS * pdpspCaps, DWORD dwFlags) PURE;
+ STDMETHOD_(HRESULT,GetSPCaps)(THIS_ DPN_SP_CAPS * pdpspCaps, DWORD dwFlags) PURE;
+ STDMETHOD_(HRESULT,SetSPAddressData)(THIS_ IDirectPlay8Address * pAddr) PURE;
+ STDMETHOD_(HRESULT,BuildAddressFromSPData)(THIS_ IDirectPlay8Address * pAddr, PVOID pvSPData) PURE;
+ STDMETHOD_(HRESULT,ReturnBuffer)(THIS_ void * pk, DWORD dwFlags) PURE;
+};
+#undef INTERFACE
+
+ /* IUnknown methods */
+#define IDirectPlay8ServiceProvider_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IDirectPlay8ServiceProvider_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IDirectPlay8ServiceProvider_Release(p) (p)->lpVtbl->Release(p)
+ /* IDirectPlay8ServiceProvider methods */
+#define IDirectPlay8ServiceProvider_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c)
+#define IDirectPlay8ServiceProvider_SendTo(p,a,b,c,d) (p)->lpVtbl->SendTo(p,a,b,c,d)
+#define IDirectPlay8ServiceProvider_SetSPCaps(p,a,b) (p)->lpVtbl->SetSPCaps(p,a,b)
+#define IDirectPlay8ServiceProvider_GetSPCaps(p,a,b) (p)->lpVtbl->GetSPCaps(p,a,b)
+#define IDirectPlay8ServiceProvider_SetSPAddressData(p,a) (p)->lpVtbl->SetSPAddressData(p,a)
+#define IDirectPlay8ServiceProvider_BuildAddressFromSPData(p,a,b) (p)->lpVtbl->BuildAddressFromSPData(p,a,b)
+#define IDirectPlay8ServiceProvider_ReturnBuffer(p,a,b) (p)->lpVtbl->ReturnBuffer(p,a,b)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WINE_DPLAY8SP_H__ */
diff --git a/dlls/dpnet/dpnet_classfactory.c b/dlls/dpnet/dpnet_classfactory.c
new file mode 100644
index 0000000..be09b93
--- /dev/null
+++ b/dlls/dpnet/dpnet_classfactory.c
@@ -0,0 +1,174 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+
+#include "dplay8.h"
+#include "dplobby8.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+typedef struct
+{
+ /* IUnknown fields */
+ const IClassFactoryVtbl *lpVtbl;
+ DWORD ref;
+ HRESULT (*pfnCreateInstance)(IUnknown *pOuter, REFIID riid,
+ LPVOID *ppobj);
+} IClassFactoryImpl;
+
+static HRESULT WINAPI
+DPCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj)
+{
+ /*ICOM_THIS(IClassFactoryImpl, iface);*/
+
+ FIXME("(%p)->(%s, %p): stub\n", iface, debugstr_guid(riid), ppobj);
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI DPCF_AddRef(LPCLASSFACTORY iface)
+{
+ ICOM_THIS(IClassFactoryImpl,iface);
+ return ++(This->ref);
+}
+
+static ULONG WINAPI DPCF_Release(LPCLASSFACTORY iface)
+{
+ ICOM_THIS(IClassFactoryImpl,iface);
+ /* static class, won't be freed */
+ return --(This->ref);
+}
+
+static HRESULT WINAPI
+DPCF_CreateInstance(LPCLASSFACTORY iface,
+ LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj)
+{
+ ICOM_THIS(IClassFactoryImpl,iface);
+
+ TRACE("(%p)->(%p,%s,%p)\n",iface,pOuter,debugstr_guid(riid),ppobj);
+ return This->pfnCreateInstance(pOuter, riid, ppobj);
+}
+
+static HRESULT WINAPI DPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
+{
+ /*ICOM_THIS(IClassFactoryImpl,iface);*/
+ FIXME("(%p)->(%d),stub!\n",iface,dolock);
+ return S_OK;
+}
+
+static const IClassFactoryVtbl DPCF_Vtbl =
+{
+ DPCF_QueryInterface,
+ DPCF_AddRef,
+ DPCF_Release,
+ DPCF_CreateInstance,
+ DPCF_LockServer
+};
+
+static IClassFactoryImpl DPNET_CF_Client = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8Client };
+static IClassFactoryImpl DPNET_CF_Server = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8Server };
+static IClassFactoryImpl DPNET_CF_Peer = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8Peer };
+
+static IClassFactoryImpl DPNET_CF_LobbiedApplication = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8LobbiedApplication };
+static IClassFactoryImpl DPNET_CF_LobbyClient = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8LobbyClient };
+
+static IClassFactoryImpl DPNET_CF_Address = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8Address };
+
+static IClassFactoryImpl DPNET_CF_ThreadPool = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8ThreadPool };
+
+static IClassFactoryImpl DPNET_CF_SP_TCPIP = {&DPCF_Vtbl, 1, DPNET_CreateDirectPlay8SP_TCPIP };
+
+/***********************************************************************
+ * DllGetClassObject (DPNET.@)
+ */
+HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid,
+ LPVOID *ppv)
+{
+ TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+
+ if (!IsEqualGUID(riid, &IID_IClassFactory) &&
+ !IsEqualGUID(riid, &IID_IUnknown))
+ {
+ ERR("(%s, %s, %p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+ return CLASS_E_CLASSNOTAVAILABLE;
+ }
+
+ if (IsEqualGUID(rclsid, &CLSID_DirectPlay8Client))
+ {
+ DPCF_AddRef((IClassFactory*)&DPNET_CF_Client);
+ *ppv = &DPNET_CF_Client;
+ return S_OK;
+ }
+ else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8Server))
+ {
+ DPCF_AddRef((IClassFactory*)&DPNET_CF_Server);
+ *ppv = &DPNET_CF_Server;
+ return S_OK;
+ }
+ else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8Peer))
+ {
+ DPCF_AddRef((IClassFactory*)&DPNET_CF_Peer);
+ *ppv = &DPNET_CF_Peer;
+ return S_OK;
+ }
+ else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8LobbiedApplication))
+ {
+ DPCF_AddRef((IClassFactory*)&DPNET_CF_LobbiedApplication);
+ *ppv = &DPNET_CF_LobbiedApplication;
+ return S_OK;
+ }
+ else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8LobbyClient))
+ {
+ DPCF_AddRef((IClassFactory*)&DPNET_CF_LobbyClient);
+ *ppv = &DPNET_CF_LobbyClient;
+ return S_OK;
+ }
+ else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8Address))
+ {
+ DPCF_AddRef((IClassFactory*)&DPNET_CF_Address);
+ *ppv = &DPNET_CF_Address;
+ return S_OK;
+ }
+ else if (IsEqualGUID(rclsid, &CLSID_DirectPlay8ThreadPool))
+ {
+ DPCF_AddRef((IClassFactory*)&DPNET_CF_ThreadPool);
+ *ppv = &DPNET_CF_ThreadPool;
+ return S_OK;
+ }
+ else if (IsEqualGUID(rclsid, &CLSID_DP8SP_TCPIP))
+ {
+ DPCF_AddRef((IClassFactory*)&DPNET_CF_SP_TCPIP);
+ *ppv = &DPNET_CF_SP_TCPIP;
+ return S_OK;
+ }
+ ERR("(%s, %s, %p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
diff --git a/dlls/dpnet/dpnet_main.c b/dlls/dpnet/dpnet_main.c
index 44788d4..d8e692a 100644
--- a/dlls/dpnet/dpnet_main.c
+++ b/dlls/dpnet/dpnet_main.c
@@ -1,7 +1,7 @@
-/*
- * DirectPlay
- *
- * Copyright 2004 Raphael Junqueira
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -16,139 +16,86 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
*/
-#include "config.h"
#include <stdarg.h>
+#include <string.h>
+
#include "windef.h"
#include "winbase.h"
-#include "wingdi.h"
#include "winuser.h"
-#include "objbase.h"
+#include "winreg.h"
#include "wine/debug.h"
+#include "winerror.h"
#include "dplay8.h"
-/*
- *#include "dplobby8.h"
- *#include "dplay8sp.h"
- */
-#include "dpnet_private.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
-WINE_DEFAULT_DEBUG_CHANNEL(dpnet);
+/***********************************************************************
+ * DllMain [Internal]
+ */
-/* At process attach */
-BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
+BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
- TRACE("%p,%x,%p\n", hInstDLL, fdwReason, lpvReserved);
- if (fdwReason == DLL_PROCESS_ATTACH) {
- DisableThreadLibraryCalls(hInstDLL);
- }
- return TRUE;
+ TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DPNET_HostNameDialogInit(hinstDLL);
+ DPNET_StartParse();
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ DPNET_StopParse();
+ DPNET_HostNameDialogUninit();
+ break;
+ }
+
+ return TRUE;
}
/***********************************************************************
* DirectPlay8Create (DPNET.@)
+ * Old and unused thesedays.
*/
-HRESULT WINAPI DirectPlay8Create(REFGUID lpGUID, LPVOID *ppvInt, LPUNKNOWN punkOuter)
+HRESULT WINAPI DirectPlay8Create(CONST CLSID* pcIID, LPVOID* ppvInterface, IUnknown* pUnknown)
{
- TRACE("(%s, %p, %p): stub\n", debugstr_guid(lpGUID), ppvInt, punkOuter);
+ TRACE("(%s, %p, %p): stub\n", debugstr_guid(pcIID), ppvInterface, pUnknown);
return S_OK;
}
-/*******************************************************************************
- * DirectPlay ClassFactory
+/***********************************************************************
+ * DllCanUnloadNow (DPNET.@)
*/
-typedef struct
+HRESULT WINAPI DllCanUnloadNow(void)
{
- /* IUnknown fields */
- const IClassFactoryVtbl *lpVtbl;
- LONG ref;
- REFCLSID rclsid;
- HRESULT (*pfnCreateInstanceFactory)(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj);
-} IClassFactoryImpl;
-
-static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
- IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-
- FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
- return E_NOINTERFACE;
-}
-
-static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) {
- IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
- return InterlockedIncrement(&This->ref);
-}
-
-static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) {
- IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
- /* static class, won't be freed */
- return InterlockedDecrement(&This->ref);
-}
-
-static HRESULT WINAPI DICF_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj) {
- IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-
- TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
- return This->pfnCreateInstanceFactory(iface, pOuter, riid, ppobj);
-}
-
-static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
- IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
- FIXME("(%p)->(%d),stub!\n",This,dolock);
- return S_OK;
+ FIXME("(void): stub\n");
+ return S_OK;
}
-static const IClassFactoryVtbl DICF_Vtbl = {
- DICF_QueryInterface,
- DICF_AddRef,
- DICF_Release,
- DICF_CreateInstance,
- DICF_LockServer
-};
-
-static IClassFactoryImpl DPNET_CFS[] = {
- { &DICF_Vtbl, 1, &CLSID_DirectPlay8Client, DPNET_CreateDirectPlay8Client },
- { &DICF_Vtbl, 1, &CLSID_DirectPlay8Server, DPNET_CreateDirectPlay8Server },
- { &DICF_Vtbl, 1, &CLSID_DirectPlay8Peer, DPNET_CreateDirectPlay8Peer },
- { &DICF_Vtbl, 1, &CLSID_DirectPlay8Address, DPNET_CreateDirectPlay8Address },
- { NULL, 0, NULL, NULL }
-};
-
/***********************************************************************
- * DllCanUnloadNow (DPNET.@)
+ * DllRegisterServer (DPNET.@)
*/
-HRESULT WINAPI DllCanUnloadNow(void)
+HRESULT WINAPI DllRegisterServer(void)
{
- return S_FALSE;
+ FIXME("(void): stub\n");
+ return S_OK;
}
/***********************************************************************
- * DllGetClassObject (DPNET.@)
+ * DllUnregisterServer (DPNET.@)
*/
-HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+HRESULT WINAPI DllUnregisterServer(void)
{
- int i = 0;
-
- TRACE("(%p,%p,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
- /*
- if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
- *ppv = (LPVOID)&DPNET_CF;
- IClassFactory_AddRef((IClassFactory*)*ppv);
- return S_OK;
- }
- */
- while (NULL != DPNET_CFS[i].rclsid) {
- if (IsEqualGUID(rclsid, DPNET_CFS[i].rclsid)) {
- DICF_AddRef((IClassFactory*) &DPNET_CFS[i]);
- *ppv = &DPNET_CFS[i];
- return S_OK;
- }
- ++i;
- }
-
- FIXME("(%p,%p,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
- return CLASS_E_CLASSNOTAVAILABLE;
+ FIXME("(void): stub\n");
+ return S_OK;
}
+
diff --git a/dlls/dpnet/general.c b/dlls/dpnet/general.c
new file mode 100644
index 0000000..7983b62
--- /dev/null
+++ b/dlls/dpnet/general.c
@@ -0,0 +1,291 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "wine/unicode.h"
+
+#include "dplay8.h"
+#include "dplay8_private.h"
+
+#define WINE_UNICODE_REWRITE
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+/* File that holds miscilanous functions used by all main DirectPlay8 classee */
+
+WCHAR *DPNET_strndupW(WCHAR *pwszSource, int len)
+{
+ WCHAR *pwszNewString;
+
+ if (!pwszSource) return NULL;
+ if (strlenW(pwszSource) < len)
+ len = strlenW(pwszSource);
+ pwszNewString = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len + 1) * sizeof(WCHAR));
+ memcpy(pwszNewString, pwszSource, len * sizeof(WCHAR));
+ pwszNewString[len] = '\0';
+ return pwszNewString;
+}
+
+WCHAR *DPNET_strdupW(WCHAR *pwszSource)
+{
+ return DPNET_strndupW(pwszSource, strlenW(pwszSource));
+}
+
+DPNET_AsyncOp* DPNET_AsyncAlloc(DirectPlay8GlobalData *dp8gdData, DWORD dwType, DWORD dwSize)
+{
+ DPNET_AsyncOp* aop = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DPNET_AsyncOp) + dwSize);
+ aop->dwType = dwType;
+ aop->PackBuffer.dwBufferSize = dwSize;
+ aop->PackBuffer.pBufferData = (LPVOID)(aop+1);
+ return aop;
+}
+
+HRESULT DPNET_AsyncFree(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop)
+{
+/* HRESULT ret = aop->result; */
+ HRESULT ret = S_OK;
+
+ /* sanity check */
+ if (aop->prev || aop->next ||
+ dp8gdData->aop_head == aop ||
+ dp8gdData->aop_tail == aop) {
+ FIXME("aop not unlinked before free!! expect crash!!\n");
+ }
+
+ if (aop->pAddrHost) IDirectPlay8Address_Release(aop->pAddrHost);
+ if (aop->pAddrDev) IDirectPlay8Address_Release(aop->pAddrDev);
+ if (aop->hSyncEvent) CloseHandle(aop->hSyncEvent);
+ HeapFree(GetProcessHeap(), 0, aop);
+ return ret;
+}
+
+void DPNET_AsyncSetSync(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop)
+{
+ aop->hSyncEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+}
+
+void DPNET_AsyncSignal(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop)
+{
+ if (aop->hSyncEvent) {
+ SetEvent(aop->hSyncEvent);
+ } else {
+ DPNET_AsyncFree(dp8gdData, aop);
+ }
+}
+
+void DPNET_AsyncWait(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop)
+{
+ /* if thread pool has no threads, we should call DoWork or something */
+ WaitForSingleObject(aop->hSyncEvent, INFINITE);
+}
+
+void DPNET_AsyncInsert(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop)
+{
+ EnterCriticalSection(&dp8gdData->cs_aop);
+ aop->prev = dp8gdData->aop_tail;
+ aop->next = NULL;
+ dp8gdData->aop_tail = aop;
+ if (!aop->prev) dp8gdData->aop_head = aop;
+ LeaveCriticalSection(&dp8gdData->cs_aop);
+}
+
+void DPNET_AsyncRemove(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop)
+{
+ EnterCriticalSection(&dp8gdData->cs_aop);
+ if (aop->prev) aop->prev->next = aop->next;
+ else dp8gdData->aop_head = aop->next;
+ aop->prev = NULL;
+ if (aop->next) aop->next->prev = aop->prev;
+ else dp8gdData->aop_tail = aop->prev;
+ aop->next = NULL;
+ LeaveCriticalSection(&dp8gdData->cs_aop);
+}
+
+DPNET_AsyncOp* DPNET_AsyncSearch(DirectPlay8GlobalData *dp8gdData, DWORD dwType, DWORD dwID)
+{
+ DPNET_AsyncOp *aop;
+ EnterCriticalSection(&dp8gdData->cs_aop);
+ aop = dp8gdData->aop_head;
+ while (aop) {
+ if (aop->dwType == dwType && aop->dwID == dwID)
+ break;
+ aop = aop->next;
+ }
+ LeaveCriticalSection(&dp8gdData->cs_aop);
+ return aop;
+}
+
+HRESULT DPNET_ObjInit(DirectPlay8GlobalData *dp8gdData, PVOID const pvUserContext,
+ const PFNDPNMESSAGEHANDLER pfn, const DWORD dwFlags)
+{
+ dp8gdData->pfMessageHandler = pfn;
+ dp8gdData->pvUserContext = pvUserContext;
+ dp8gdData->dpnCaps.dwSize = sizeof(DPN_CAPS);
+ dp8gdData->dpnCaps.dwFlags = 0;
+ dp8gdData->dpnCaps.dwConnectTimeout = 2000;
+ dp8gdData->dpnCaps.dwConnectRetries = 14;
+ dp8gdData->dpnCaps.dwTimeoutUntilKeepAlive = 60000;
+ InitializeCriticalSection(&dp8gdData->cs_aop);
+ InitializeCriticalSection(&dp8gdData->cs_player);
+ InitializeCriticalSection(&dp8gdData->localPlayer.cs);
+ dp8gdData->localPlayer.dplay_ver = 7;
+ return S_OK;
+}
+
+void DPNET_ObjFree(DirectPlay8GlobalData *dp8gdData)
+{
+ int i;
+ DPNET_AsyncOp *aop;
+
+ TRACE("%p\n", dp8gdData);
+
+ DPNET_KillPlayers(dp8gdData);
+
+ for (i = 0; i < dp8gdData->SPAvailableCount; i++)
+ {
+ HeapFree(GetProcessHeap(), 0, dp8gdData->pSPAvailable[i].pwszName);
+ }
+ HeapFree(GetProcessHeap(), 0, dp8gdData->pSPAvailable);
+ dp8gdData->SPAvailableCount = 0;
+ if (dp8gdData->sp)
+ {
+ IDirectPlay8ServiceProvider_Release(dp8gdData->sp);
+ }
+
+ DeleteCriticalSection(&dp8gdData->localPlayer.cs);
+ DeleteCriticalSection(&dp8gdData->cs_player);
+
+ EnterCriticalSection(&dp8gdData->cs_aop);
+ aop = dp8gdData->aop_head;
+ while (aop) {
+ DPNET_AsyncOp *next_aop = aop->next;
+ DPNET_AsyncFree(dp8gdData, aop);
+ aop = next_aop;
+ }
+ LeaveCriticalSection(&dp8gdData->cs_aop);
+ DeleteCriticalSection(&dp8gdData->cs_aop);
+
+ HeapFree(GetProcessHeap(), 0, dp8gdData);
+}
+
+DWORD DPNET_Random(DirectPlay8GlobalData *dp8gdData)
+{
+ /* this is probably random enough for our purposes. */
+ return GetTickCount() * 524287;
+}
+
+HRESULT DPNET_EnumServiceProviders(DirectPlay8GlobalData *dp8gdData,
+ const GUID *const pguidServiceProvider,
+ const GUID *const pguidApplication,
+ DPN_SERVICE_PROVIDER_INFO * pSPInfoBuffer,
+ DWORD * pcbEnumData,
+ DWORD * pcReturned,
+ const DWORD dwFlags)
+{
+ TRACE("(%s, %s, %p, %p (%i), %p, 0x%08x)\n",
+ debugstr_guid(pguidServiceProvider), debugstr_guid(pguidApplication),
+ pSPInfoBuffer, pcbEnumData, *pcbEnumData, pcReturned, dwFlags);
+
+ if (pguidServiceProvider)
+ {
+ FIXME("ignoring pguidServiceProvider\n");
+ }
+ if (pguidApplication)
+ {
+ FIXME("ignoring pguidApplication\n");
+ }
+ if (dwFlags && dwFlags & ~DPNENUMSERVICEPROVIDERS_ALL)
+ {
+ FIXME("unrecognised flags\n");
+ }
+
+ if (!dp8gdData->pSPAvailable) /* must fill our structure of available service providers */
+ {
+ HKEY kDPSPRoot;
+ DWORD subKeys, maxSubKeyLen;
+ LPSTR lpSubKeyBuffer;
+ int i;
+
+ RegOpenKeyA(HKEY_LOCAL_MACHINE,
+ "Software\Microsoft\DirectPlay8\Service Providers", &kDPSPRoot);
+ RegQueryInfoKeyA(kDPSPRoot, NULL, NULL, NULL, &subKeys, &maxSubKeyLen,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ dp8gdData->pSPAvailable = HeapAlloc(GetProcessHeap(), 0, sizeof(DPN_SERVICE_PROVIDER_INFO) * subKeys);
+ dp8gdData->SPAvailableCount = subKeys;
+ lpSubKeyBuffer = HeapAlloc(GetProcessHeap(), 0, maxSubKeyLen + 1);
+ for (i = 0; i < subKeys; i++)
+ {
+ HKEY kDPSP;
+ DWORD RegValueSize;
+ LPSTR lpRegValue;
+ LPWSTR lpRegValueW;
+ int WCharNameSize;
+
+ RegEnumKeyA(kDPSPRoot, i, lpSubKeyBuffer, maxSubKeyLen + 1);
+ RegOpenKeyA(kDPSPRoot, lpSubKeyBuffer, &kDPSP);
+
+ dp8gdData->pSPAvailable[i].dwFlags = 0;
+
+ RegQueryValueExA(kDPSP, "Friendly Name", 0, NULL, NULL, &RegValueSize);
+ lpRegValue = HeapAlloc(GetProcessHeap(), 0, RegValueSize);
+ RegQueryValueExA(kDPSP, "Friendly Name", 0, NULL, (LPBYTE)lpRegValue, &RegValueSize);
+ WCharNameSize = RegValueSize * sizeof(WCHAR) / sizeof(CHAR);
+ dp8gdData->pSPAvailable[i].pwszName = HeapAlloc(GetProcessHeap(), 0, WCharNameSize);
+ MultiByteToWideChar(CP_ACP, 0, lpRegValue, -1, dp8gdData->pSPAvailable[i].pwszName,
+ WCharNameSize);
+ HeapFree(GetProcessHeap(), 0, lpRegValue);
+
+ RegQueryValueExA(kDPSP, "GUID", 0, NULL, NULL, &RegValueSize);
+ lpRegValue = HeapAlloc(GetProcessHeap(), 0, RegValueSize);
+ lpRegValueW = HeapAlloc(GetProcessHeap(), 0, RegValueSize * sizeof(WCHAR) / sizeof(CHAR));
+ RegQueryValueExA(kDPSP, "GUID", 0, NULL, (LPBYTE)lpRegValue, &RegValueSize);
+ MultiByteToWideChar(CP_ACP, 0, lpRegValue, -1, lpRegValueW,
+ RegValueSize * sizeof(WCHAR) / sizeof(CHAR));
+ CLSIDFromString(lpRegValueW, &dp8gdData->pSPAvailable[i].guid);
+ HeapFree(GetProcessHeap(), 0, lpRegValue);
+ HeapFree(GetProcessHeap(), 0, lpRegValueW);
+
+ dp8gdData->pSPAvailable[i].pvReserved = 0;
+ dp8gdData->pSPAvailable[i].dwReserved = 0;
+ }
+ HeapFree(GetProcessHeap(), 0, lpSubKeyBuffer);
+ }
+ if (*pcbEnumData < sizeof(DPN_SERVICE_PROVIDER_INFO) * dp8gdData->SPAvailableCount)
+ {
+ *pcbEnumData = sizeof(DPN_SERVICE_PROVIDER_INFO) * dp8gdData->SPAvailableCount;
+ *pcReturned = 0;
+ return DPNERR_BUFFERTOOSMALL;
+ }
+ /* FIXME: shouldn't use memcpy :( */
+ memcpy(pSPInfoBuffer, dp8gdData->pSPAvailable, sizeof(DPN_SERVICE_PROVIDER_INFO) * dp8gdData->SPAvailableCount);
+ *pcReturned = dp8gdData->SPAvailableCount;
+ return S_OK;
+}
diff --git a/dlls/dpnet/hostname_En.rc b/dlls/dpnet/hostname_En.rc
new file mode 100755
index 0000000..7e5fab0
--- /dev/null
+++ b/dlls/dpnet/hostname_En.rc
@@ -0,0 +1,39 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "windef.h"
+#include "winuser.h"
+#include "winnls.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+HOSTNAME DIALOG LOADONCALL MOVEABLE DISCARDABLE 0, 0, 192, 68
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
+CAPTION "Enter host name"
+FONT 8, "Helv"
+{
+ DEFPUSHBUTTON "OK", IDOK, 135, 7, 50, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 135, 24, 50, 14
+ LTEXT "Enter the remote machine address:", -1, 7, 7, 114, 11
+ EDITTEXT 701, 7, 48, 178, 13, ES_AUTOHSCROLL
+}
+
+#include "version.rc"
+
diff --git a/dlls/dpnet/lobbiedapp.c b/dlls/dpnet/lobbiedapp.c
new file mode 100644
index 0000000..1ae6f1f
--- /dev/null
+++ b/dlls/dpnet/lobbiedapp.c
@@ -0,0 +1,132 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+
+#include "dplay8.h"
+#include "dplobby8.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+static ICOM_VTABLE(IDirectPlay8LobbiedApplication) directPlay8LobbiedApplicationVT;
+
+HRESULT WINAPI
+DirectPlay8LobbiedApplication_QueryInterface(PDIRECTPLAY8LOBBIEDAPPLICATION iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS(IDirectPlay8LobbiedApplicationImpl, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDirectPlay8LobbiedApplication, riid))
+ {
+ This->ref++;
+ *obj = This;
+ return S_OK;
+ }
+ else
+ {
+ FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj);
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG WINAPI
+DirectPlay8LobbiedApplication_AddRef(PDIRECTPLAY8LOBBIEDAPPLICATION iface)
+{
+ ICOM_THIS(IDirectPlay8LobbiedApplicationImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ return ++This->ref;
+}
+
+ULONG WINAPI
+DirectPlay8LobbiedApplication_Release(PDIRECTPLAY8LOBBIEDAPPLICATION iface)
+{
+ ICOM_THIS(IDirectPlay8LobbiedApplicationImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ if (--This->ref) return This->ref;
+
+ FIXME("destroy this and everything\n");
+
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+}
+
+HRESULT WINAPI
+DirectPlay8LobbiedApplication_Initialize(PDIRECTPLAY8LOBBIEDAPPLICATION iface,
+ const PVOID pvUserContext,
+ const PFNDPNMESSAGEHANDLER pfn,
+ DPNHANDLE * const pdpnhConnection,
+ const DWORD dwFlags)
+{
+ /*ICOM_THIS(IDirectPlay8LobbiedApplicationImpl, iface);*/
+ FIXME("(%p)->(%p, %p, %p, 0x%08x): stub. Lobbying not supported, you _may_ be able to ignore this\n",
+ iface, pvUserContext,
+ pfn, pdpnhConnection, dwFlags);
+ *pdpnhConnection = (DPNHANDLE)NULL;
+ return S_OK;
+}
+
+HRESULT
+DPNET_CreateDirectPlay8LobbiedApplication(IUnknown *pOuter, REFIID riid, LPVOID *ppobj)
+{
+ IDirectPlay8LobbiedApplicationImpl *ipDP8LA;
+ HRESULT hr;
+ TRACE("()\n");
+ ipDP8LA = (IDirectPlay8LobbiedApplicationImpl *)
+ HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(IDirectPlay8LobbiedApplicationImpl));
+ if (ipDP8LA == NULL) return E_OUTOFMEMORY;
+ ICOM_VTBL(ipDP8LA) = &directPlay8LobbiedApplicationVT;
+ IDirectPlay8LobbiedApplication_AddRef((IDirectPlay8LobbiedApplication *)ipDP8LA);
+ TRACE("Created new interface: %p\n", ipDP8LA);
+ hr = IDirectPlay8LobbiedApplication_QueryInterface((IDirectPlay8LobbiedApplication *)ipDP8LA, riid, ppobj);
+ IDirectPlay8LobbiedApplication_Release((IDirectPlay8LobbiedApplication *)ipDP8LA);
+ if (SUCCEEDED(hr))
+ return S_OK;
+ else
+ return E_NOINTERFACE;
+}
+
+static ICOM_VTABLE(IDirectPlay8LobbiedApplication) directPlay8LobbiedApplicationVT =
+{
+ DirectPlay8LobbiedApplication_QueryInterface,
+ DirectPlay8LobbiedApplication_AddRef,
+ DirectPlay8LobbiedApplication_Release,
+ DirectPlay8LobbiedApplication_Initialize,
+ (void*)0xdead5005, /* RegisterProgram */
+ (void*)0xdead5006, /* UnRegisterProgram */
+ (void*)0xdead5007, /* Send */
+ (void*)0xdead5008, /* SetAppAvailable */
+ (void*)0xdead5009, /* UpdateStatus */
+ (void*)0xdead500a, /* Close */
+ (void*)0xdead500b, /* GetConnectionSettings */
+ (void*)0xdead500c /* SetConnectionSettings */
+};
+
diff --git a/dlls/dpnet/lobbyclient.c b/dlls/dpnet/lobbyclient.c
new file mode 100644
index 0000000..7fe6eec
--- /dev/null
+++ b/dlls/dpnet/lobbyclient.c
@@ -0,0 +1,116 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+
+#include "dplay8.h"
+#include "dplobby8.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+static ICOM_VTABLE(IDirectPlay8LobbyClient) directPlay8LobbyClientVT;
+
+HRESULT WINAPI
+DirectPlay8LobbyClient_QueryInterface(PDIRECTPLAY8LOBBYCLIENT iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS(IDirectPlay8LobbyClientImpl, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDirectPlay8LobbyClient, riid))
+ {
+ This->ref++;
+ *obj = This;
+ return S_OK;
+ }
+ else
+ {
+ FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj);
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG WINAPI
+DirectPlay8LobbyClient_AddRef(PDIRECTPLAY8LOBBYCLIENT iface)
+{
+ ICOM_THIS(IDirectPlay8LobbyClientImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ return ++This->ref;
+}
+
+ULONG WINAPI
+DirectPlay8LobbyClient_Release(PDIRECTPLAY8LOBBYCLIENT iface)
+{
+ ICOM_THIS(IDirectPlay8LobbyClientImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ if (--This->ref) return This->ref;
+
+ FIXME("destroy this and everything\n");
+
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+}
+
+HRESULT
+DPNET_CreateDirectPlay8LobbyClient(IUnknown *pOuter, REFIID riid, LPVOID *ppobj)
+{
+ IDirectPlay8LobbyClientImpl *ipDP8LC;
+ HRESULT hr;
+ TRACE("()\n");
+ ipDP8LC = (IDirectPlay8LobbyClientImpl *)
+ HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(IDirectPlay8LobbyClientImpl));
+ if (ipDP8LC == NULL) return E_OUTOFMEMORY;
+ ICOM_VTBL(ipDP8LC) = &directPlay8LobbyClientVT;
+ IDirectPlay8LobbyClient_AddRef((IDirectPlay8LobbyClient *)ipDP8LC);
+ TRACE("Created new interface: %p\n", ipDP8LC);
+ hr = IDirectPlay8LobbyClient_QueryInterface((IDirectPlay8LobbyClient *)ipDP8LC, riid, ppobj);
+ IDirectPlay8LobbyClient_Release((IDirectPlay8LobbyClient *)ipDP8LC);
+ if (SUCCEEDED(hr))
+ return S_OK;
+ else
+ return E_NOINTERFACE;
+}
+
+static ICOM_VTABLE(IDirectPlay8LobbyClient) directPlay8LobbyClientVT =
+{
+ DirectPlay8LobbyClient_QueryInterface,
+ DirectPlay8LobbyClient_AddRef,
+ DirectPlay8LobbyClient_Release,
+ (void*)0xdead6004, /* Initialize */
+ (void*)0xdead6005, /* EnumLocalPrograms */
+ (void*)0xdead6006, /* ConnectApplication */
+ (void*)0xdead6007, /* Send */
+ (void*)0xdead6008, /* ReleaseApplication */
+ (void*)0xdead6009, /* Close */
+ (void*)0xdead600a, /* GetConnectionSettings */
+ (void*)0xdead600b /* SetConnectionSettings */
+};
+
diff --git a/dlls/dpnet/parse.c b/dlls/dpnet/parse.c
new file mode 100644
index 0000000..48d7dca
--- /dev/null
+++ b/dlls/dpnet/parse.c
@@ -0,0 +1,152 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+#include <stdarg.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "wine/unicode.h"
+
+#include "nmapi.h"
+#include "dplay8.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+HMODULE hParse, hNM;
+PPF_PARSERDLLINFO info;
+
+static HPROTOCOL WINAPI (*pCreateProtocol)(LPCSTR ProtocolName, LPENTRYPOINTS lpEntryPoints, DWORD cbEntryPoints);
+static HPROTOCOL WINAPI (*pGetProtocolFromName)(LPCSTR ProtocolName);
+static void WINAPI (*pParsePacket)(HPROTOCOL pprot, HPROTOCOL prot, LPVOID pkt, DWORD size, DWORD hsize);
+
+LPVOID dllinfo;
+HPROTOCOL udp, dpsp;
+CRITICAL_SECTION parse_cs;
+
+void DPNET_GetParseInfo(void)
+{
+ /* this is not necessary, I think */
+#if 0
+ PARSERAUTOINSTALLINFO install_info;
+
+ install_info = (LPVOID)GetProcAddress(hParse, "ParserAutoInstallInfo");
+ info = install_info();
+ TRACE("got parser info: %p\n", info);
+#endif
+}
+
+void DPNET_StartParse(void)
+{
+ TRACE("loading dp8parse.dll\n");
+ hParse = LoadLibraryA("dp8parse.dll");
+ if (!hParse) {
+ TRACE("- dp8parse.dll not found, protocol parsing unavailable\n");
+ return;
+ }
+ hNM = LoadLibraryA("nmapi.dll");
+ if (!hNM) {
+ FreeLibrary(hParse);
+ hParse = 0;
+ TRACE("- nmapi.dll not found, protocol parsing unavailable\n");
+ return;
+ }
+ pParsePacket = (LPVOID)GetProcAddress(hNM, "wine_ParsePacket");
+ if (!pParsePacket) {
+ FreeLibrary(hNM);
+ hNM = 0;
+ FreeLibrary(hParse);
+ hParse = 0;
+ TRACE("- not using builtin nmapi.dll, protocol parsing unavailable\n");
+ return;
+ }
+ pCreateProtocol = (LPVOID)GetProcAddress(hNM, "CreateProtocol");
+ pGetProtocolFromName = (LPVOID)GetProcAddress(hNM, "GetProtocolFromName");
+ InitializeCriticalSection(&parse_cs);
+
+ DPNET_GetParseInfo();
+
+ udp = pCreateProtocol("UDP", NULL, 0);
+
+ dpsp = pGetProtocolFromName("DPLAYSP");
+}
+
+void DPNET_StopParse(void)
+{
+ if (!hParse) return;
+ DeleteCriticalSection(&parse_cs);
+ TRACE("unloading dp8parse.dll\n");
+ FreeLibrary(hNM);
+ hNM = 0;
+ FreeLibrary(hParse);
+ hParse = 0;
+}
+
+typedef struct {
+ WORD sport;
+ WORD dport;
+ WORD len;
+ WORD cksum;
+} UDP;
+
+void DPNET_ParsePacket(int proto, struct sockaddr_in *from, struct sockaddr_in *to,
+ const DPN_BUFFER_DESC *buf, const DWORD bufs)
+{
+ UDP *hdr;
+ LPBYTE ptr;
+ DWORD c, len;
+
+ if (!hParse) return;
+
+ len = 0;
+ for (c=0; c<bufs; c++)
+ len += buf[c].dwBufferSize;
+
+ hdr = HeapAlloc(GetProcessHeap(), 0, sizeof(UDP) + len);
+ hdr->sport = from ? from->sin_port : htons(2302);
+ hdr->dport = to ? to->sin_port : htons(2302);
+ hdr->len = htons(sizeof(UDP) + len);
+ hdr->cksum = 0; /* not important */
+ ptr = (LPBYTE)(hdr+1);
+ for (c=0; c<bufs; c++) {
+ memcpy(ptr, buf[c].pBufferData, buf[c].dwBufferSize);
+ ptr += buf[c].dwBufferSize;
+ }
+
+ /* serializing the parsing makes for cleaner traces. */
+ EnterCriticalSection(&parse_cs);
+
+ TRACE("from port %d to port %d, payload %d bytes\n", ntohs(hdr->sport), ntohs(hdr->dport), len);
+
+ pParsePacket(udp, dpsp, hdr, sizeof(UDP) + len, sizeof(UDP));
+
+ LeaveCriticalSection(&parse_cs);
+
+ HeapFree(GetProcessHeap(), 0, hdr);
+}
diff --git a/dlls/dpnet/peer.c b/dlls/dpnet/peer.c
index cb4b638..3d95c39 100644
--- a/dlls/dpnet/peer.c
+++ b/dlls/dpnet/peer.c
@@ -1,7 +1,7 @@
-/*
- * DirectPlay8 Peer
- *
- * Copyright 2004 Raphael Junqueira
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -16,26 +16,401 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
*/
-#include "config.h"
-
#include <stdarg.h>
-
+#include <string.h>
#include "windef.h"
#include "winbase.h"
-#include "wingdi.h"
#include "winuser.h"
+#include "winreg.h"
#include "objbase.h"
#include "wine/debug.h"
+#include "winerror.h"
+#include "winnt.h"
#include "dplay8.h"
-#include "dpnet_private.h"
+#include "dplay8_private.h"
+
+#define WINE_UNICODE_REWRITE
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+static ICOM_VTABLE(IDirectPlay8Peer) directPlay8PeerVT;
+
+HRESULT WINAPI DirectPlay8Peer_QueryInterface(PDIRECTPLAY8PEER iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDirectPlay8Peer, riid))
+ {
+ This->ref++;
+ *obj = This;
+ return S_OK;
+ }
+ else
+ {
+ FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj);
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG WINAPI DirectPlay8Peer_AddRef(PDIRECTPLAY8PEER iface)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ return ++This->ref;
+}
+
+ULONG WINAPI DirectPlay8Peer_Release(PDIRECTPLAY8PEER iface)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ if (--This->ref) return This->ref;
+
+ DPNET_ObjFree(&This->dp8gdData);
+
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+}
+
+HRESULT WINAPI DirectPlay8Peer_Initialize(PDIRECTPLAY8PEER iface, PVOID const pvUserContext,
+ const PFNDPNMESSAGEHANDLER pfn, const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%p, %p, 0x%08x)\n", iface, pvUserContext, pfn, dwFlags);
+ return DPNET_ObjInit(&This->dp8gdData, pvUserContext, pfn, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_EnumServiceProviders(PDIRECTPLAY8PEER iface,
+ const GUID *const pguidServiceProvider,
+ const GUID *const pguidApplication,
+ DPN_SERVICE_PROVIDER_INFO *const pSPInfoBuffer,
+ DWORD *const pcbEnumData, DWORD *const pcReturned,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%s, %s, %p, %p (%i), %p, 0x%08x)\n",
+ iface, debugstr_guid(pguidServiceProvider), debugstr_guid(pguidApplication),
+ pSPInfoBuffer, pcbEnumData, *pcbEnumData, pcReturned, dwFlags);
+ return DPNET_EnumServiceProviders(&This->dp8gdData, pguidServiceProvider, pguidApplication,
+ pSPInfoBuffer, pcbEnumData, pcReturned, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_GetPeerAddress(PDIRECTPLAY8PEER iface,
+ const DPNID dpnid,
+ IDirectPlay8Address **const pAddress,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ dpPlayer *cur;
+
+ TRACE("(%p)->(%i, %p, %08x)\n", iface, dpnid, pAddress, dwFlags);
+
+ cur = This->dp8gdData.remotePlayers;
+
+ while (cur)
+ {
+ if (cur->dwPlayerID == dpnid)
+ {
+ *pAddress = cur->pAddress;
+ IDirectPlay8Address_AddRef(*pAddress);
+ return S_OK;
+ }
+ cur = cur->next;
+ }
+
+ /* we don't check local player, this is correct. local player isn't checked */
+ return DPNERR_INVALIDPLAYER;
+}
+
+
+HRESULT WINAPI DirectPlay8Peer_GetLocalHostAddresses(PDIRECTPLAY8PEER iface,
+ IDirectPlay8Address **const prgpAddress,
+ DWORD *const pcAddress,
+ const DWORD dwFlags)
+{
+ /*ICOM_THIS(IDirectPlay8PeerImpl, iface);*/
+ FIXME("(%p)->(%p, %p, 0x%08x): semi-stub\n", iface, prgpAddress, pcAddress, dwFlags);
+
+ return DPNERR_NOTHOST;
+}
+
+HRESULT WINAPI DirectPlay8Peer_Close(PDIRECTPLAY8PEER iface, const DWORD dwFlags)
+{
+ FIXME("(%p)->(0x%08x)\n", iface, dwFlags);
+ return S_OK;
+}
+
+HRESULT WINAPI DirectPlay8Peer_EnumHosts(PDIRECTPLAY8PEER iface, PDPN_APPLICATION_DESC const pApplicationDesc,
+ IDirectPlay8Address *const pAddrHost, IDirectPlay8Address *const pDeviceInfo,
+ PVOID const pUserEnumData, const DWORD dwUserEnumDataSize,
+ const DWORD dwEnumCount, const DWORD dwRetryInterval,
+ const DWORD dwTimeOut, PVOID const pvUserContext, DPNHANDLE *const pAsyncHandle,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%p, %p, %p, %p, %i, %i, %i, %i, %p, %p, 0x%08x)\n", iface, pApplicationDesc, pAddrHost,
+ pDeviceInfo, pUserEnumData, dwUserEnumDataSize, dwEnumCount, dwRetryInterval, dwTimeOut,
+ pvUserContext, pAsyncHandle, dwFlags);
+ return DPNET_EnumHosts(&This->dp8gdData, pApplicationDesc, pAddrHost,
+ pDeviceInfo, pUserEnumData, dwUserEnumDataSize, dwEnumCount,
+ dwRetryInterval, dwTimeOut, pvUserContext, pAsyncHandle, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_CancelAsyncOperation(PDIRECTPLAY8PEER iface, const DPNHANDLE hAsyncHandle,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(0x%08x, 0x%08x)\n", iface, hAsyncHandle, dwFlags);
+ return DPNET_CancelAsyncOperation(&This->dp8gdData, hAsyncHandle, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_Connect(PDIRECTPLAY8PEER iface,
+ const DPN_APPLICATION_DESC *const pdnAppDesc,
+ IDirectPlay8Address *const pHostAddr,
+ IDirectPlay8Address *const pDeviceInfo,
+ const DPN_SECURITY_DESC *const pdnSecurity,
+ const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
+ const void *const pvUserConnectData,
+ const DWORD dwUserConnectDataSize,
+ void *const pvPlayerContext, void *const pvAsyncContext,
+ DPNHANDLE *const phAsyncHandle, const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+
+ TRACE("(%p)->(%p, %p, %p, %p, %p, %p, %i, %p, %p, %p, 0x%08x)\n", iface, pdnAppDesc,
+ pHostAddr, pDeviceInfo, pdnSecurity, pdnCredentials, pvUserConnectData,
+ dwUserConnectDataSize, pvPlayerContext, pvAsyncContext, phAsyncHandle, dwFlags);
+ if (pdnSecurity || pdnCredentials)
+ FIXME("we do not yet support securtity stuff.. Either does dplay8 or 9\n");
+ memcpy(&This->dp8gdData.appdesc.guidApplication, &pdnAppDesc->guidApplication, sizeof(GUID));
+ memcpy(&This->dp8gdData.appdesc.guidInstance, &pdnAppDesc->guidInstance, sizeof(GUID));
-WINE_DEFAULT_DEBUG_CHANNEL(dpnet);
+ return DPNET_Connect(&This->dp8gdData, pdnAppDesc, pHostAddr, pDeviceInfo,
+ pdnSecurity, pdnCredentials, pvUserConnectData,
+ dwUserConnectDataSize, pvPlayerContext, pvAsyncContext,
+ phAsyncHandle, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_SendTo(PDIRECTPLAY8PEER iface, const DPNID dpnid,
+ const DPN_BUFFER_DESC *const pBufferDesc, const DWORD cBufferDesc,
+ const DWORD dwTimeOut, void *const pvAsyncContext,
+ DPNHANDLE *const phAsyncHandle, const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%i, %p, %i, %i, %p, %p, 0x%08x)\n", iface, dpnid, pBufferDesc, cBufferDesc,
+ dwTimeOut, pvAsyncContext, phAsyncHandle, dwFlags);
+ return DPNET_SendTo(&This->dp8gdData, dpnid, pBufferDesc, cBufferDesc,
+ dwTimeOut, pvAsyncContext, phAsyncHandle, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_Host(PDIRECTPLAY8PEER iface,
+ const DPN_APPLICATION_DESC *const pdnAppDesc,
+ IDirectPlay8Address **const prgpDeviceInfo,
+ const DWORD cDeviceInfo,
+ const DPN_SECURITY_DESC *const pdpSecurity,
+ const DPN_SECURITY_CREDENTIALS *const pdpCredentials,
+ VOID *const pvPlayerContext,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+
+ TRACE("(%p)->(%p, %p, %i, %p, %p, %p, 0x%08x)\n", iface, pdnAppDesc,
+ prgpDeviceInfo, cDeviceInfo, pdpSecurity, pdpCredentials, pvPlayerContext,
+ dwFlags);
+ if (pdpSecurity || pdpCredentials)
+ FIXME("we do not yet support securtity stuff.. Either does dplay8 or 9\n");
-HRESULT DPNET_CreateDirectPlay8Peer(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
- WARN("(%p, %s, %p): stub.\n", punkOuter, debugstr_guid(riid), ppobj);
- return CLASS_E_CLASSNOTAVAILABLE;
+ memcpy(&This->dp8gdData.appdesc.guidApplication, &pdnAppDesc->guidApplication, sizeof(GUID));
+ CoCreateGuid(&This->dp8gdData.appdesc.guidInstance);
+
+ return DPNET_Host(&This->dp8gdData, pdnAppDesc, prgpDeviceInfo, cDeviceInfo,
+ pdpSecurity, pdpCredentials, pvPlayerContext, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_GetApplicationDesc(PDIRECTPLAY8PEER iface,
+ DPN_APPLICATION_DESC *const pAppDescBuffer,
+ DWORD *const pcbDataSize,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%p, %p (%i), 0x%08x)\n", iface, pAppDescBuffer,
+ pcbDataSize, *pcbDataSize, dwFlags);
+ return DPNET_GetApplicationDesc(&This->dp8gdData, pAppDescBuffer, pcbDataSize, dwFlags);
}
+
+
+HRESULT WINAPI DirectPlay8Peer_EnumPlayersAndGroups(PDIRECTPLAY8PEER iface,
+ DPNID *const prgdpnid,
+ DWORD *const pcdpnid,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ int count;
+ dpPlayer *cur;
+
+ TRACE("(%p)->(%p, %p (%08i), %08x)\n", iface, prgdpnid, pcdpnid, *pcdpnid, dwFlags);
+
+ if (!(dwFlags & DPNENUM_PLAYERS))
+ {
+ FIXME("only support enumeration of players\n");
+ return DPNERR_INVALIDFLAGS;
+ }
+
+ count = 1; /* local */
+
+ cur = This->dp8gdData.remotePlayers;
+ while (cur)
+ {
+ count++;
+ cur = cur->next;
+ }
+
+ if (*pcdpnid < count)
+ {
+ *pcdpnid = count;
+ return DPNERR_BUFFERTOOSMALL;
+ }
+
+ count = 0;
+ prgdpnid[count++] = This->dp8gdData.localPlayer.dwPlayerID;
+ cur = This->dp8gdData.remotePlayers;
+ while (cur)
+ {
+ prgdpnid[count] = cur->dwPlayerID;
+ count++;
+ cur = cur->next;
+ }
+
+ return S_OK;
+}
+
+HRESULT WINAPI DirectPlay8Peer_SetPeerInfo(PDIRECTPLAY8PEER iface,
+ const DPN_PLAYER_INFO *const pdpnPlayerInfo,
+ PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%p, %p, %p, 0x%08x)\n", iface, pdpnPlayerInfo,
+ pvAsyncContext, phAsyncHandle, dwFlags);
+ return DPNET_SetPeerInfo(&This->dp8gdData, pdpnPlayerInfo, pvAsyncContext, phAsyncHandle, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_GetPeerInfo(PDIRECTPLAY8PEER iface, const DPNID dpnid,
+ DPN_PLAYER_INFO *const pdpnPlayerInfo,
+ DWORD *const pdwSize, const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%x, %p, %p (%i), 0x%08x)\n", iface, dpnid,
+ pdpnPlayerInfo, pdwSize, *pdwSize, dwFlags);
+ return DPNET_GetPeerInfo(&This->dp8gdData, dpnid, pdpnPlayerInfo, pdwSize, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_ReturnBuffer(PDIRECTPLAY8PEER iface, const DPNHANDLE hBufferHandle,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%i, 0x%08x)\n", iface, hBufferHandle, dwFlags);
+ return DPNET_ReturnBuffer(&This->dp8gdData, hBufferHandle, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_GetPlayerContext(PDIRECTPLAY8PEER iface, const DPNID dpnid,
+ PVOID *const ppvPlayerContext, const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%i, %p, 0x%08x)\n", iface, dpnid, ppvPlayerContext, dwFlags);
+ return DPNET_GetPlayerContext(&This->dp8gdData, dpnid, ppvPlayerContext, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_GetCaps(PDIRECTPLAY8PEER iface, DPN_CAPS *const pdpCaps,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%p, 0x%08x)\n", iface, pdpCaps, dwFlags);
+ return DPNET_GetCaps(&This->dp8gdData, pdpCaps, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_GetSPCaps(PDIRECTPLAY8PEER iface, const GUID *const pguidSP,
+ DPN_SP_CAPS *const pdpnSPCaps,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8PeerImpl, iface);
+ TRACE("(%p)->(%s, %p, 0x%08x)\n", iface, debugstr_guid(pguidSP),
+ pdpnSPCaps, dwFlags);
+ return DPNET_GetSPCaps(&This->dp8gdData, pguidSP, pdpnSPCaps, dwFlags);
+}
+
+HRESULT WINAPI DirectPlay8Peer_TerminateSession(PDIRECTPLAY8PEER iface,
+ void *const pvTerminateData,
+ const DWORD dwTerminateDataSize,
+ const DWORD dwFlags)
+{
+ /*ICOM_THIS(IDirectPlay8PeerImpl, iface);*/
+ FIXME("(%p): stub\n", iface);
+ return S_OK;
+}
+
+
+HRESULT DPNET_CreateDirectPlay8Peer(IUnknown *pOuter, REFIID riid, LPVOID *ppobj)
+{
+ IDirectPlay8PeerImpl *ipDP8P;
+ HRESULT hr;
+ TRACE("()\n");
+ ipDP8P = (IDirectPlay8PeerImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(IDirectPlay8PeerImpl));
+ if (ipDP8P == NULL) return E_OUTOFMEMORY;
+ ICOM_VTBL(ipDP8P) = &directPlay8PeerVT;
+ IDirectPlay8Peer_AddRef((IDirectPlay8Peer *)ipDP8P);
+ TRACE("Created new object: %p\n", ipDP8P);
+ hr = IDirectPlay8Peer_QueryInterface((IDirectPlay8Peer *)ipDP8P, riid, ppobj);
+ IDirectPlay8Peer_Release((IDirectPlay8Peer *)ipDP8P);
+ if (SUCCEEDED(hr))
+ return S_OK;
+ else
+ return E_NOINTERFACE;
+}
+
+static ICOM_VTABLE(IDirectPlay8Peer) directPlay8PeerVT =
+{
+ DirectPlay8Peer_QueryInterface,
+ DirectPlay8Peer_AddRef,
+ DirectPlay8Peer_Release,
+ DirectPlay8Peer_Initialize,
+ DirectPlay8Peer_EnumServiceProviders,
+ DirectPlay8Peer_CancelAsyncOperation,
+ DirectPlay8Peer_Connect,
+ DirectPlay8Peer_SendTo,
+ (void*)0xdead2009, /* GetSendQueueInfo */
+ DirectPlay8Peer_Host, /* Host */
+ DirectPlay8Peer_GetApplicationDesc,
+ (void*)0xdead200c, /* SetApplicationDesc */
+ (void*)0xdead200d, /* CreateGroup */
+ (void*)0xdead200e, /* DestroyGroup */
+ (void*)0xdead200f, /* AddPlayerToGroup */
+ (void*)0xdead2010, /* RemovePlayerFromGroup */
+ (void*)0xdead2011, /* SetGroupInfo */
+ (void*)0xdead2012, /* GetGroupInfo */
+ DirectPlay8Peer_EnumPlayersAndGroups,
+ (void*)0xdead2014, /* EnumGroupMembers */
+ DirectPlay8Peer_SetPeerInfo,
+ DirectPlay8Peer_GetPeerInfo,
+ DirectPlay8Peer_GetPeerAddress,
+ DirectPlay8Peer_GetLocalHostAddresses,
+ DirectPlay8Peer_Close,
+ DirectPlay8Peer_EnumHosts,
+ (void*)0xdead201b, /* DestroyPeer */
+ DirectPlay8Peer_ReturnBuffer,
+ DirectPlay8Peer_GetPlayerContext,
+ (void*)0xdead201e, /* GetGroupContext */
+ DirectPlay8Peer_GetCaps,
+ (void*)0xdead2020, /* SetCaps */
+ (void*)0xdead2021, /* SetSPCaps */
+ DirectPlay8Peer_GetSPCaps,
+ (void*)0xdead2023, /* GetConnectionInfo */
+ (void*)0xdead2024, /* RegisterLobby */
+ DirectPlay8Peer_TerminateSession
+};
+
diff --git a/dlls/dpnet/protocol.h b/dlls/dpnet/protocol.h
new file mode 100644
index 0000000..c210e2f
--- /dev/null
+++ b/dlls/dpnet/protocol.h
@@ -0,0 +1,289 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_PROTOCOL_H
+#define __WINE_PROTOCOL_H
+
+#include "dplay8.h"
+#include "dplobby8.h"
+
+#include "pshpack1.h"
+
+/* message type magic numbers */
+
+#define DP8P_ENUMHOSTS 0x00
+#define DP8P_CONNECT 0x88
+#define DP8P_SETPEERINFO 0x7F
+#define DP8P_MESSAGEDATA 0x37
+#define DP8P_MESSAGEDATA_UNKNOWN 0x3D
+#define DP8P_MESSAGEDATA_GUARANTEED 0x3F
+#define DP8P_ACK 0x80
+
+/* ENUMHOSTS */
+
+#define DP8P_ENUMHOSTS_SEND 0x02
+#define DP8P_ENUMHOSTS_RESPONSE 0x03
+
+typedef struct dp8pmsg_EnumHostsSend
+{
+ BYTE protocol_magic;
+ BYTE enum_type; /* ENUMHOST_SEND. */
+ BYTE packet_count;
+ BYTE unknown_03; /* 0x82 */
+ BYTE unknown_04; /* 0x01 */
+ GUID guidApp;
+} dp8pmsg_EnumHostsSend;
+
+typedef struct dp8pmsg_EnumHostsResponse
+{
+ BYTE protocol_magic;
+ BYTE enum_type; /* ENUMHOST_RESPONSE. */
+ BYTE packet_count;
+ BYTE unknown_03; /* 0x82 */
+ BYTE unknown_04; /* 0x00 */
+ BYTE unknown_05[7]; /* 0x00 */
+ BYTE unknown_12; /* ed */
+ BYTE unknown_13; /* 8f */
+ BYTE unknown_14; /* f0 */
+ BYTE unknown_15; /* b7 */
+ DWORD unknown_16; /* 0x00 */
+ DWORD max_players;
+ DWORD current_players; /* ?? unconfirmed */
+ DWORD unknown_28; /* 0x58 */
+ DWORD unknown_32; /* 0x12 */
+ BYTE unknown_36[24]; /* 0x00 */
+ GUID guidUnknown;
+ GUID guidApp;
+ WCHAR game_name[0]; /* null terminate wide string */
+} dp8pmsg_EnumHostsResponse;
+
+/* ACK */
+/* response to message data (3f): 80 06 01 00 04 [05] 00 00 76 13 D8 04
+ * (3f): 80 06 01 00 02 [02] 00 00 8e a7 6c 00 ( same session as below ) ( at time = 1.751872 )
+ * response to server connect (88): 80 02 01 00 02 [00] 01 00 d9 11 36 6b 81 a7 6c 00 (at time = 1.729208)
+ * pid - sometimes its +1, odd. hrm, just seen it as +2, gah.
+ * type. not really sure. (doesnt change from packet to packet)
+ * player id, to/from?
+ */
+typedef struct dp8pmsg_Ack
+{
+ BYTE protocol_magic;
+ BYTE reply_type;
+ BYTE unknown_03; /* 01 */
+ BYTE unknown_04; /* 00 */
+ BYTE unknown_05; /* player ID maybe? */
+ BYTE orig_packet_count; /* packet count of the one we are replying to, kinda */
+ BYTE unknown_07;
+ BYTE unknown_08;
+ BYTE data[0];
+ /* so far always includes:
+ * DWORD time_recieved; (from GetTickCount()) at end
+ * has also included another DWORD in connect replies, this dword is the same
+ * as the one we send out in 'connect' packets */
+} dp8pmsg_Ack;
+
+/* CONNECT */
+
+/* go 1:
+ connect : 88 01 00 00 02 00 01 00 41 44 fe 72 a3 c7 14 00
+ sresponse : 88 02 00 00 05 00 01 00 41 44 fe 72 ea a9 10 00
+ --- Server recieves DPN_MSGID_INIDCATE_CONNECT here (after response)... odd
+ cresponse : 80 02 01 00 02 00 01 00 41 44 fe 72 ab c7 14 00 (ack)
+ */
+/* go 2:
+ connect : 88 01 00 00 02 00 01 00 c1 61 74 00 79 b2 4c 00
+ sresponse : 88 02 00 00 05 00 01 00 c1 61 74 00 9b 94 48 00
+ cresponse : 80 02 01 00 02 00 01 00 c1 61 74 00 80 b2 4c 00
+ */
+
+typedef struct dp8pmsg_Connect
+{
+ BYTE protocol_magic;
+ BYTE connect_type; /* 01 = connect, 02 = reply && connect to non-host peers. */
+ BYTE packet_count; /* if so, it resets at 0. */
+ BYTE unknown_04; /* 0x00 */
+ BYTE unknown_05; /* 0x02 */
+ BYTE unknown_06; /* 0x00 */
+ BYTE unknown_07; /* 0x01 */
+ BYTE unknown_08; /* 0x00 */
+ /* FIXME: this unknown below MIGHT MATTER.. if so, I need to find out why?? */
+ DWORD unknown_09; /* ... */ /* probably a dword of something... */
+ DWORD time_sent; /* from GetTickCount() */
+} dp8pmsg_Connect;
+
+/* SETPEERINFO */
+
+/*
+ 7f 00 01 00 c1 00 ......
+00 00 04 00 00 00 02 00 00 00 50 00 00 00 10 00 ........ ..P.....
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00 00 b6 5d c1 46 26 50 f5 44 95 51 f4 bd af 3b ...].F&P .D.Q...;
+11 c1 36 30 6a 87 d7 ff bc 46 92 09 b4 2f 61 7b ..60j... .F.../a{
+9b e7 4d 00 61 00 72 00 69 00 73 00 69 00 61 00 ..M.a.r. i.s.i.a.
+00 00 ..
+
+*/
+/*
+ 7f 00 01 02 c2 00 ........ !.......
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00 00 00 00 00 00 03 00 00 00 f8 01 00 00 12 00 ........ ........
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00 00 00 00 00 00 00 00 00 00 d2 e9 04 2e c5 30 ........ .......0
+f2 42 b5 28 93 ea 11 b0 55 ab 36 30 6a 87 d7 ff .B.(.... U.60j...
+bc 46 92 09 b4 2f 61 7b 9b e7|d6 e9 54 2e 05 00 .F.../a{ ....T...
+00 00 00 00 00 00 03 00 00 00 00 00 00 00|d0 e9 ........ ........
+24 2e 00 00 00 00 02 01 00 00 02 00 00 00 00 00 $....... ........ -- host
+00 00 06 00 00 00 ea 01 00 00 0e 00 00 00 00 00 ........ ........
+00 00 00 00 00 00 00 00 00 00 00 00 00 00|d1 e9 ........ ........
+34 2e 00 00 00 00 00 01 00 00 03 00 00 00 00 00 4....... ........ -- other player
+00 00 06 00 00 00 d6 01 00 00 14 00 00 00 00 00 ........ ........
+00 00 00 00 00 00 74 01 00 00 62 00 00 00|d6 e9 ......t. ..b.....
+54 2e 00 00 00 00 00 01 00 00 05 00 00 00 00 00 T....... ........
+00 00 02 00 00 00 5e 01 00 00 16 00 00 00 00 00 ......^. ........ -- us ?
+00 00 00 00 00 00 fc 00 00 00 62 00 00 00|78 2d ........ ..b...x-
+64 69 72 65 63 74 70 6c 61 79 3a 2f 70 72 6f 76 directpl ay:/prov
+69 64 65 72 3d 25 37 42 45 42 46 45 37 42 41 30 ider=%7B EBFE7BA0
+2d 36 32 38 44 2d 31 31 44 32 2d 41 45 30 46 2d -628D-11 D2-AE0F-
+30 30 36 30 39 37 42 30 31 34 31 31 25 37 44 3b 006097B0 1411%7D; -- 120 (78) is len of uri + name
+68 6f 73 74 6e 61 6d 65 3d 31 39 32 2e 31 36 38 hostname =192.168 -- 98 (62) is len of uri
+2e 30 2e 31 39 3b 70 6f 72 74 3d 32 33 30 32 00 .0.19;po rt=2302.
+54 00 65 00 73 00 74 00 50 00 6c 00 61 00 79 00 T.e.s.t. P.l.a.y. -- 22 (16) is len of name
+65 00 72 00 00 00 78 2d 64 69 72 65 63 74 70 6c e.r...x- directpl
+61 79 3a 2f 70 72 6f 76 69 64 65 72 3d 25 37 42 ay:/prov ider=%7B
+45 42 46 45 37 42 41 30 2d 36 32 38 44 2d 31 31 EBFE7BA0 -628D-11
+44 32 2d 41 45 30 46 2d 30 30 36 30 39 37 42 30 D2-AE0F- 006097B0 -- 118 (76) is len of uri + name
+31 34 31 31 25 37 44 3b 68 6f 73 74 6e 61 6d 65 1411%7D; hostname -- 98 (62) is len of uri
+3d 31 39 32 2e 31 36 38 2e 30 2e 32 37 3b 70 6f =192.168 .0.27;po
+72 74 3d 32 33 30 33 00 43 00 6c 00 69 00 65 00 rt=2303. C.l.i.e. -- 20 (14) is len of name
+6e 00 74 00 54 00 77 00 6f 00 00 00 43 00 6c 00 n.t.T.w. o...C.l.
+69 00 65 00 6e 00 74 00 00 00 54 00 65 00 73 00 i.e.n.t. ..T.e.s. -- 14 ( e) is len of name
+74 00 47 00 61 00 6d 00 65 00 00 00 t.G.a.m. e... -- 18 (12) is len of game name
+
+*/
+typedef struct dp8pmsg_SetPeerInfo_Local
+{
+ BYTE protocol_magic;
+ BYTE unknown_02;
+ BYTE packet_count;
+ BYTE unknown_04; /* 00 */ /* -- peer type ID? */
+ DWORD unknown_05; /* 0xc1 */
+ DWORD unknown_09; /* 0x04 */
+ DWORD unknown_13; /* 0x02 */
+ DWORD unknown_17; /* 0x50, civ3 has 0x58 - perhaps offset to name or something? */
+ DWORD player_name_len;
+
+ DWORD unknown_21; /* 00 */
+ DWORD unknown_25;
+ DWORD unknown_29;
+ DWORD unknown_33;
+ DWORD unknown_37; /* 0x50 for civ3 */
+ DWORD connect_data_len;
+ DWORD unknown_45;
+ DWORD unknown_49;
+ GUID guidUnknown;
+ GUID guidApp;
+ BYTE data[0];
+} dp8pmsg_SetPeerInfo_Local;
+
+typedef struct dp8pmsg_SetPeerInfo_Game
+{
+ BYTE protocol_magic;
+ BYTE unknown_02;
+ BYTE packet_count;
+ BYTE unknown_04; /* 02 */ /* -- peer type ID? */
+ DWORD unknown_05; /* c2 */ /* also possibly peer type ID, maybe flags? */
+ DWORD unknown_09; /* saw 0x78 01 00 00 when we had data, could be offset? */
+ DWORD reply_data_len;
+ BYTE unknown_17[12];
+ DWORD player_count; /* FIXME: or our player number */
+ DWORD len_unknown_01; /* offset? length of something. its rather odd */
+ DWORD game_name_len;
+ BYTE unknown_x1[24];
+ GUID guidUnknown;
+ GUID guidApp;
+ DWORD unknown_x2;
+ DWORD our_player_number;
+ DWORD unknown_x4; /* 0 */
+ DWORD player_count_2; /* FIXME: or our player number */
+ DWORD unknown_x5; /* 0 */
+ BYTE data[0]; /* dp8pmsg_part_PeerInfo_Player * number of players. +
+ * (uri + player name) * number of players +
+ * game name
+ */
+} dp8pmsg_SetPeerInfo_Game;
+
+typedef struct dp8pmsg_part_PeerInfo_Player
+{
+ DPNID player_id;
+ DWORD unknown_05; /* 0 */
+ DWORD unknown_09; /* something rather interesting, indeed */
+ DWORD player_number; /* player number, internal? unique in a session */
+ DWORD unknown_17; /* 0 */
+ DWORD unknown_21; /* 06 for other? 02 for the person recieving the message? */
+ DWORD unknown_25; /* some kind of count, odd really */
+ DWORD player_name_len;
+ DWORD unknown_33; /* 0 */
+ DWORD player_data_len;
+ DWORD unknown_41; /* something rather high, normally */
+ DWORD uri_len;
+} dp8pmsg_part_PeerInfo_Player;
+
+typedef struct dp8pmsg_SetPeerInfo_Unknown
+/* I'm not sure why this is used, I need more testing.
+ * I'm thinking it may be for sending "hello" to each peer? */
+{
+ BYTE protocol_magic;
+ BYTE unknown_02;
+ BYTE packet_count;
+ BYTE unknown_04; /* 02 */
+ BYTE unknown_05; /* c3 to send. c5 to recieve rejected, c6 to recieve ok */
+ BYTE unknown_06; /* 00 */
+ BYTE unknown_07; /* 00 */
+ BYTE unknown_08; /* 00 */
+} dp8pmsg_SetPeerInfo_Unknown;
+
+typedef struct dp8pmsg_SetPeerInfo_Connected
+{ /* probably shouldn't be called SetPeerInfo */
+ BYTE protocol_magic;
+ BYTE unknown_02;
+ BYTE packet_count;
+ BYTE unknown_04;
+ DWORD unknown_05; /* c5 = rejected, c6 = accepted */
+ DWORD unknown_09; /* 0x80158260 */
+ DWORD unknown_13; /* 0 (sample) or 0xc (civ3 rejected) */
+ DWORD data_size; /* 0 or 0x21 == length of data */
+ BYTE data[0];
+} dp8pmsg_SetPeerInfo_Connected;
+
+/* MESSAGEDATA */
+
+typedef struct dp8pmsg_MessageData
+{
+ BYTE protocol_magic;
+ BYTE unknown_02; /* 00 */
+ BYTE packet_count;
+ BYTE unknown_04;
+ BYTE data[0];
+} dp8pmsg_MessageData;
+
+#include "poppack.h"
+
+#endif
diff --git a/dlls/dpnet/server.c b/dlls/dpnet/server.c
index 085b15f..05506bb 100644
--- a/dlls/dpnet/server.c
+++ b/dlls/dpnet/server.c
@@ -1,7 +1,7 @@
-/*
- * DirectPlay8 Server
- *
- * Copyright 2004 Raphael Junqueira
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -16,26 +16,115 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
*/
-#include "config.h"
-
#include <stdarg.h>
-
+#include <string.h>
#include "windef.h"
#include "winbase.h"
-#include "wingdi.h"
#include "winuser.h"
+#include "winreg.h"
#include "objbase.h"
#include "wine/debug.h"
+#include "winerror.h"
#include "dplay8.h"
-#include "dpnet_private.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+static ICOM_VTABLE(IDirectPlay8Server) directPlay8ServerVT;
+
+HRESULT WINAPI DirectPlay8Server_QueryInterface(PDIRECTPLAY8SERVER iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS(IDirectPlay8ServerImpl, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDirectPlay8Server, riid))
+ {
+ This->ref++;
+ *obj = This;
+ return S_OK;
+ }
+ else
+ {
+ FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj);
+ return E_NOINTERFACE;
+ }
+}
-WINE_DEFAULT_DEBUG_CHANNEL(dpnet);
+ULONG WINAPI DirectPlay8Server_AddRef(PDIRECTPLAY8SERVER iface)
+{
+ ICOM_THIS(IDirectPlay8ServerImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ return ++This->ref;
+}
+
+ULONG WINAPI DirectPlay8Server_Release(PDIRECTPLAY8SERVER iface)
+{
+ ICOM_THIS(IDirectPlay8ServerImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ if (--This->ref) return This->ref;
+
+ FIXME("destroy this and everything\n");
+
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+}
-HRESULT DPNET_CreateDirectPlay8Server(LPCLASSFACTORY iface, LPUNKNOWN punkOuter, REFIID riid, LPVOID *ppobj) {
- WARN("(%p, %s, %p): stub.\n", punkOuter, debugstr_guid(riid), ppobj);
- return CLASS_E_CLASSNOTAVAILABLE;
+HRESULT DPNET_CreateDirectPlay8Server(IUnknown *pOuter, REFIID riid, LPVOID *ppobj)
+{
+ IDirectPlay8ServerImpl *ipDP8S;
+ HRESULT hr;
+ TRACE("()\n");
+ ipDP8S = (IDirectPlay8ServerImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(IDirectPlay8ServerImpl));
+ if (ipDP8S == NULL) return E_OUTOFMEMORY;
+ ICOM_VTBL(ipDP8S) = &directPlay8ServerVT;
+ IDirectPlay8Server_AddRef((IDirectPlay8Server *)ipDP8S);
+ TRACE("Created new object: %p\n", ipDP8S);
+ hr = IDirectPlay8Server_QueryInterface((IDirectPlay8Server *)ipDP8S, riid, ppobj);
+ IDirectPlay8Server_Release((IDirectPlay8Server *)ipDP8S);
+ if (SUCCEEDED(hr))
+ return S_OK;
+ else
+ return E_NOINTERFACE;
}
+
+static ICOM_VTABLE(IDirectPlay8Server) directPlay8ServerVT =
+{
+ DirectPlay8Server_QueryInterface,
+ DirectPlay8Server_AddRef,
+ DirectPlay8Server_Release,
+ (void*)0xdead4004, /* Initilize */
+ (void*)0xdead4005, /* EnumServiceProviers */
+ (void*)0xdead4006, /* CancelAsyncOperation */
+ (void*)0xdead4007, /* GetSendQueueInfo */
+ (void*)0xdead4008, /* GetApplicationDesc */
+ (void*)0xdead4009, /* SetServerInfo */
+ (void*)0xdead400a, /* GetClientInfo */
+ (void*)0xdead400b, /* GetClientAddress */
+ (void*)0xdead400c, /* GetLocalHostAddresses */
+ (void*)0xdead400d, /* SetApplicationDesc */
+ (void*)0xdead400e, /* Host */
+ (void*)0xdead400f, /* SendTo */
+ (void*)0xdead4010, /* CreateGroup */
+ (void*)0xdead4011, /* DestroyGroup */
+ (void*)0xdead4012, /* AddPlayerToGroup */
+ (void*)0xdead4013, /* RemovePlayerFromGroup */
+ (void*)0xdead4014, /* SetGroupInfo */
+ (void*)0xdead4015, /* GetGroupInfo */
+ (void*)0xdead4016, /* EnumPlayersAndGroups */
+ (void*)0xdead4017, /* Close */
+ (void*)0xdead4018, /* DestroyClient */
+ (void*)0xdead4019, /* ReturnBuffer */
+ (void*)0xdead401a, /* GetPlayerContext */
+ (void*)0xdead401b, /* GetGroupContext */
+ (void*)0xdead401c, /* SetCaps */
+ (void*)0xdead401d, /* GetCaps */
+ (void*)0xdead401e, /* GetConnectionInfo */
+ (void*)0xdead401f /* RegisterLobby */
+};
+
+
diff --git a/dlls/dpnet/session.c b/dlls/dpnet/session.c
new file mode 100644
index 0000000..cfb11ae
--- /dev/null
+++ b/dlls/dpnet/session.c
@@ -0,0 +1,2373 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+#include "winnt.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "wine/unicode.h"
+
+#include "dplay8.h"
+#include "dplay8_private.h"
+
+/* DirectPlay 8 session protocol */
+
+#include "pshpack1.h"
+
+/* some packets seem to change with the version
+ * first message packet:
+ * ver 5: 3f 00 00 00 (first packet)
+ * 3f 01 00 00 (retransmits)
+ * ver 6: 3f 02 00 00 <conn id> (first packet)
+ * 3f 03 00 00 <conn id> (retransmits)
+ */
+#define DP8SESS_DEFVER MAKELONG(5, 1)
+#define DP8SESS_MINVER(a,b) min(a,b)
+
+typedef struct {
+ DWORD size;
+ DWORD flags;
+ DWORD max_players;
+ DWORD cur_players;
+ /* ofs 16 */
+ DWORD name_ofs;
+ DWORD name_size;
+ DWORD pass_ofs;
+ DWORD pass_size;
+ /* ofs 32 */
+ DWORD res_ofs;
+ DWORD res_size;
+ DWORD appres_ofs;
+ DWORD appres_size;
+ /* ofs 48 */
+ GUID instGUID;
+ /* ofs 64 */
+ GUID appGUID;
+ /* ofs 80 */
+} DP8_AppDesc;
+
+#define DP8SESS_TAG 0
+#define DP8SESS_ENUM_REQUEST 2
+#define DP8SESS_ENUM_RESPONSE 3
+
+#define DP8SESS_ENUM_REQ_WITH_GUID 1
+#define DP8SESS_ENUM_REQ_WITHOUT_GUID 2
+
+typedef struct {
+ BYTE tag;
+ BYTE command;
+ WORD id;
+ /* ofs 4 */
+ BYTE type;
+} DP8_EnumRequest;
+
+typedef struct {
+ BYTE tag;
+ BYTE command;
+ WORD id;
+ /* ofs 4 */
+ DWORD reply_ofs;
+ DWORD reply_size;
+ /* ofs 12 */
+ DP8_AppDesc app_desc;
+ /* ofs 92 */
+} DP8_EnumResponse;
+
+#define DP8SESS_PATH_TEST 5
+
+typedef struct {
+ BYTE tag;
+ BYTE command;
+ WORD id;
+ /* ofs 4 */
+ DWORD key1;
+ DWORD key2;
+} DP8_PathTest;
+
+#define DP8SESS_CONNECT 0x88
+#define DP8SESS_CONN_REQUEST 0x01
+#define DP8SESS_CONN_RESPONSE 0x02
+
+typedef struct {
+ BYTE command;
+ BYTE type;
+ BYTE pkt;
+ BYTE unknown_03;
+ /* ofs 4 */
+ DWORD ver;
+ /* ofs 8 */
+ DWORD id;
+ DWORD time;
+ /* ofs 16 */
+} DP8_Connect;
+
+#define DP8SESS_ACKNOWLEDGE 0x80
+#define DP8SESS_ACK_CONNECT 0x02
+#define DP8SESS_ACK_DATA_RELIABLE 0x06
+
+typedef struct {
+ BYTE command;
+ BYTE type;
+ WORD unknown_02;
+ /* ofs 4 */
+ DWORD ver;
+ /* ofs 8 */
+ DWORD id;
+ DWORD time;
+ /* ofs 16 */
+} DP8_ConnAck;
+
+typedef struct {
+ BYTE command;
+ BYTE type;
+ WORD unknown_02;
+ /* ofs 4 */
+ BYTE next_out;
+ BYTE next_in;
+ WORD unknown_06;
+ /* ofs 8 */
+ DWORD time;
+ /* ofs 16 */
+} DP8_DataAck;
+
+#define DP8SESS_MESSAGE 0x7f
+
+typedef struct {
+ BYTE command;
+ BYTE type;
+ BYTE next_out;
+ BYTE next_in;
+ /* ofs 4 */
+ DWORD msg;
+ /* ofs 8 */
+} DP8_Message;
+
+#define DP8SESS_MSG_PLAYER_CONNECT 0xc1
+
+#define DP8SESS_CONNF_SERVER 0x01
+#define DP8SESS_CONNF_CLIENT 0x02
+#define DP8SESS_CONNF_PEER 0x04
+
+typedef struct {
+ DP8_Message msg;
+ /* ofs 8 */
+ DWORD flags;
+ DWORD dplay_ver;
+ DWORD name_ofs;
+ DWORD name_size;
+ DWORD data_ofs;
+ DWORD data_size;
+ DWORD pass_ofs;
+ DWORD pass_size;
+ DWORD conn_ofs;
+ DWORD conn_size;
+ DWORD url_ofs;
+ DWORD url_size;
+ GUID instGUID;
+ GUID appGUID;
+ DWORD addr_ofs;
+ DWORD addr_size;
+} DP8_PlayerConnect;
+
+#define DP8SESS_MSG_SESSION_INFO 0xc2
+
+typedef struct {
+ DP8_Message msg;
+ /* ofs 8 */
+ DWORD reply_ofs;
+ DWORD reply_size;
+ /* ofs 16 */
+ DP8_AppDesc app_desc;
+ /* ofs 96 */
+ DWORD player_id;
+ DWORD ver;
+ DWORD unknown_104;
+ DWORD entries;
+ DWORD members;
+} DP8_SessionInfo;
+
+#define DP8SESS_PINFOF_LOCAL 0x0001
+#define DP8SESS_PINFOF_HOST 0x0002
+#define DP8SESS_PINFOF_ALLPLAYER_GROUP 0x0004
+#define DP8SESS_PINFOF_GROUP 0x0010
+#define DP8SESS_PINFOF_MULTICAST_GROUP 0x0020
+#define DP8SESS_PINFOF_AUTODESTRUCT_GROUP 0x0040
+#define DP8SESS_PINFOF_PEER 0x0100
+#define DP8SESS_PINFOF_CLIENT 0x0200
+#define DP8SESS_PINFOF_SERVER 0x0400
+#define DP8SESS_PINFOF_AVAILABLE 0x1000
+#define DP8SESS_PINFOF_CONNECTING 0x2000
+#define DP8SESS_PINFOF_DISCONNECTING 0x4000
+
+typedef struct {
+ DWORD group_id;
+ DWORD owner_id;
+ DWORD flags;
+ DWORD ver;
+ /* ofs 16 */
+ DWORD unknown_16;
+ DWORD dplay_ver;
+ DWORD name_ofs;
+ DWORD name_size;
+ DWORD data_ofs;
+ DWORD data_size;
+ DWORD url_ofs;
+ DWORD url_size;
+} DP8_PlayerInfo;
+
+#define DP8SESS_MSG_SESSION_ACK 0xc3
+
+typedef struct {
+ DP8_Message msg;
+} DP8_SessionAck;
+
+#define DP8SESS_MSG_PEER_CONNECT 0xc6
+
+typedef struct {
+ DP8_Message msg;
+ /* ofs 8 */
+ DWORD player_id;
+ DWORD ver;
+ /* ofs 16 */
+ DWORD unknown_16;
+} DP8_PeerConnect;
+
+#define DP8SESS_MSG_TABLE_VER 0xc9
+
+typedef struct {
+ DP8_Message msg;
+ /* ofs 8 */
+ DWORD ver;
+ /* ofs 12 */
+ DWORD unknown_12;
+} DP8_TableVer;
+
+#define DP8SESS_MSG_APPDESC_UPDATE 0xcf
+
+typedef struct {
+ DP8_Message msg;
+ /* ofs 8 */
+ DP8_AppDesc app_desc;
+ /* ofs 88 */
+} DP8_AppDescUpdate;
+
+#define DP8SESS_DATA_UNRELIABLE 0x37
+#define DP8SESS_DATA_RELIABLE 0x3f
+
+typedef struct {
+ BYTE command;
+ BYTE type;
+ BYTE next_out;
+ BYTE next_in;
+ /* ofs 4 */
+} DP8_Data;
+
+#include "poppack.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+static BOOL DPNET_RecvPacket(DirectPlay8GlobalData *, void *, int, IDirectPlay8Address *);
+static HRESULT DPNET_StartAsync(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop);
+
+static HRESULT DPNET_InitSP(DirectPlay8GlobalData *dp8gdData, const GUID *const guidNewSP)
+{
+ if (!IsEqualGUID(guidNewSP, &dp8gdData->guidSP))
+ {
+ HRESULT hr;
+ if (dp8gdData->sp)
+ {
+ IDirectPlay8ServiceProvider_Release(dp8gdData->sp);
+ dp8gdData->sp = NULL;
+ }
+ memcpy(&dp8gdData->guidSP, guidNewSP, sizeof(GUID));
+ hr = CoCreateInstance(&dp8gdData->guidSP, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IDirectPlay8ServiceProvider,
+ (LPVOID *) &dp8gdData->sp);
+ if (SUCCEEDED(hr))
+ {
+ IDirectPlay8ServiceProvider_Initialize(dp8gdData->sp, dp8gdData, DPNET_RecvPacket, 0);
+ }
+ else
+ {
+ WARN("failed to switch to service provider %s\n", debugstr_guid(guidNewSP));
+ memset(&dp8gdData->guidSP, 0, sizeof(GUID));
+ return hr;
+
+ }
+ }
+ return S_OK;
+}
+
+static void DPNET_SetAppDesc(DirectPlay8GlobalData *dp8gdData, const DPN_APPLICATION_DESC *pdnAppDesc)
+{
+ dp8gdData->appdesc.dwMaxPlayers = max(dp8gdData->appdesc.dwCurrentPlayers, pdnAppDesc->dwMaxPlayers);
+ if (dp8gdData->appdesc.pwszSessionName != pdnAppDesc->pwszSessionName) {
+ if (dp8gdData->appdesc.pwszSessionName)
+ HeapFree(GetProcessHeap(), 0, dp8gdData->appdesc.pwszSessionName);
+ dp8gdData->appdesc.pwszSessionName = DPNET_strdupW(pdnAppDesc->pwszSessionName);
+ }
+ if (dp8gdData->appdesc.pwszPassword != pdnAppDesc->pwszPassword) {
+ if (dp8gdData->appdesc.pwszPassword)
+ HeapFree(GetProcessHeap(), 0, dp8gdData->appdesc.pwszPassword);
+ dp8gdData->appdesc.pwszPassword = DPNET_strdupW(pdnAppDesc->pwszPassword);
+ }
+ if (dp8gdData->appdesc.pvApplicationReservedData != pdnAppDesc->pvApplicationReservedData ||
+ dp8gdData->appdesc.dwApplicationReservedDataSize != pdnAppDesc->dwApplicationReservedDataSize) {
+ if (dp8gdData->appdesc.pvApplicationReservedData)
+ HeapFree(GetProcessHeap(), 0, dp8gdData->appdesc.pvApplicationReservedData);
+ if (pdnAppDesc->pvApplicationReservedData && pdnAppDesc->dwApplicationReservedDataSize) {
+ dp8gdData->appdesc.pvApplicationReservedData = HeapAlloc(GetProcessHeap(), 0, pdnAppDesc->dwApplicationReservedDataSize);
+ dp8gdData->appdesc.dwApplicationReservedDataSize = pdnAppDesc->dwApplicationReservedDataSize;
+ memcpy(dp8gdData->appdesc.pvApplicationReservedData, pdnAppDesc->pvApplicationReservedData, pdnAppDesc->dwApplicationReservedDataSize);
+ }
+ else {
+ dp8gdData->appdesc.pvApplicationReservedData = NULL;
+ dp8gdData->appdesc.dwApplicationReservedDataSize = 0;
+ }
+ }
+}
+
+static void DPNET_ReturnBufferToApp(DirectPlay8GlobalData *dp8gdData, HRESULT hr,
+ PVOID pvBuffer, PVOID pvUserContext)
+{
+ DPNMSG_RETURN_BUFFER ret;
+ if (!pvBuffer) return;
+ ret.dwSize = sizeof(ret);
+ ret.hResultCode = hr;
+ ret.pvBuffer = pvBuffer;
+ ret.pvUserContext = pvUserContext;
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_RETURN_BUFFER, &ret);
+}
+
+static dpPlayer* DPNET_FindPlayerByAddr(DirectPlay8GlobalData *dp8gdData, IDirectPlay8Address *pAddress)
+{
+ dpPlayer *play;
+ EnterCriticalSection(&dp8gdData->cs_player);
+ /* see if the service provider already identified a player */
+ play = dp8gdData->remotePlayers;
+ while (play) {
+ if (play->pAddress == pAddress) break;
+ play = play->next;
+ }
+ LeaveCriticalSection(&dp8gdData->cs_player);
+ return play;
+}
+
+static dpPlayer* DPNET_FindPlayerByID(DirectPlay8GlobalData *dp8gdData, DPNID dpnid)
+{
+ dpPlayer *play;
+ EnterCriticalSection(&dp8gdData->cs_player);
+ play = &dp8gdData->localPlayer;
+ if (play->dwPlayerID != dpnid) {
+ play = dp8gdData->remotePlayers;
+ while (play) {
+ if (play->dwPlayerID == dpnid) break;
+ play = play->next;
+ }
+ }
+ LeaveCriticalSection(&dp8gdData->cs_player);
+ return play;
+}
+
+static dpPlayer* DPNET_MakePlayer(DirectPlay8GlobalData *dp8gdData, IDirectPlay8Address *pAddress, BOOL *found)
+{
+ dpPlayer *play;
+ EnterCriticalSection(&dp8gdData->cs_player);
+ /* see if the service provider already identified a player */
+ play = dp8gdData->remotePlayers;
+ while (play) {
+ if (play->pAddress == pAddress) {
+ *found = TRUE;
+ break;
+ }
+ play = play->next;
+ }
+ if (!play) {
+ /* create new player */
+ *found = FALSE;
+ play = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dpPlayer));
+ InitializeCriticalSection(&play->cs);
+ IDirectPlay8Address_Duplicate(pAddress, &play->pAddress);
+ play->next = dp8gdData->remotePlayers;
+ dp8gdData->remotePlayers = play;
+ }
+ LeaveCriticalSection(&dp8gdData->cs_player);
+ return play;
+}
+
+static void DPNET_KillPlayer(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ EnterCriticalSection(&dp8gdData->cs_player);
+
+ /* free remote player */
+ if (play->prev) play->prev->next = play->next;
+ else dp8gdData->remotePlayers = play->next;
+ if (play->next) play->next->prev = play->prev;
+ DPNET_ReturnBufferToApp(dp8gdData, S_OK, play->conn_data, play->conn_data_ctx);
+ if (play->reply_data) HeapFree(GetProcessHeap(), 0, play->reply_data);
+ if (play->pAddress) IDirectPlay8Address_Release(play->pAddress);
+ if (play->status == PLAYER_ACTIVE)
+ dp8gdData->appdesc.dwCurrentPlayers--;
+ DeleteCriticalSection(&play->cs);
+ HeapFree(GetProcessHeap(), 0, play);
+
+ LeaveCriticalSection(&dp8gdData->cs_player);
+}
+
+void DPNET_KillPlayers(DirectPlay8GlobalData *dp8gdData)
+{
+ dpPlayer *play;
+ EnterCriticalSection(&dp8gdData->cs_player);
+
+ /* free remote players */
+ while (dp8gdData->remotePlayers) {
+ play = dp8gdData->remotePlayers;
+ dp8gdData->remotePlayers = play->next;
+ if (play->next) play->next->prev = NULL;
+ DPNET_ReturnBufferToApp(dp8gdData, S_OK, play->conn_data, play->conn_data_ctx);
+ if (play->reply_data) HeapFree(GetProcessHeap(), 0, play->reply_data);
+ if (play->pAddress) IDirectPlay8Address_Release(play->pAddress);
+ DeleteCriticalSection(&play->cs);
+ HeapFree(GetProcessHeap(), 0, play);
+ }
+
+ /* free local player */
+ play = &dp8gdData->localPlayer;
+ play->status = PLAYER_UNKNOWN;
+ if (play->conn_data) {
+ HeapFree(GetProcessHeap(), 0, play->conn_data);
+ play->conn_data = NULL;
+ play->conn_data_len = 0;
+ }
+ if (play->pAddress) IDirectPlay8Address_Release(play->pAddress);
+ play->pAddress = NULL;
+
+ dp8gdData->remoteHost = NULL;
+
+ dp8gdData->appdesc.dwCurrentPlayers = 0;
+ LeaveCriticalSection(&dp8gdData->cs_player);
+}
+
+static void DPNET_LockPlayer(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ EnterCriticalSection(&play->cs);
+}
+
+static void DPNET_UnlockPlayer(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ LeaveCriticalSection(&play->cs);
+}
+
+static BOOL DPNET_GotAck(DirectPlay8GlobalData *dp8gdData, dpPlayer *play, BYTE next_out, BYTE next_in)
+{
+ /* FIXME: what about wraparound, eh? */
+
+ if (next_in > play->next_out) {
+ TRACE("bah, there's ghosts in the machine! got %d, sent %d\n", next_in, play->next_out);
+ }
+ if (next_in > play->ack_out) {
+ /* they've received our packets */
+ TRACE("acknowledge out: from %d to %d, sent %d\n", play->ack_out, next_in, play->next_out);
+ play->ack_out = next_in;
+ }
+ else if (next_in < play->ack_out) {
+ /* they haven't received them yet */
+ TRACE("bah, we got an old acknowledge! last %d, got %d\n", play->ack_out, next_in);
+ }
+
+ if (next_out > play->next_in) {
+ /* we haven't received all their packets */
+ TRACE("bah, we're missing a packet! expected %d, got %d\n", play->next_in, next_out);
+ return FALSE;
+ }
+ else if (next_out < play->next_in) {
+ /* delayed packet? */
+ TRACE("bah, we got an old packet! expected %d, got %d\n", play->next_in, next_out);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int DPNET_ParseAppDesc(DirectPlay8GlobalData *dp8gdData, DPN_APPLICATION_DESC *tdesc, DP8_AppDesc *sdesc, LPVOID src)
+{
+ LPBYTE pk = src;
+ memset(tdesc, 0, sizeof(*tdesc));
+ tdesc->dwSize = sizeof(*tdesc);
+ tdesc->dwFlags = sdesc->flags;
+ memcpy(&tdesc->guidInstance, &sdesc->instGUID, sizeof(GUID));
+ memcpy(&tdesc->guidApplication, &sdesc->appGUID, sizeof(GUID));
+ tdesc->dwMaxPlayers = sdesc->max_players;
+ tdesc->dwCurrentPlayers = sdesc->cur_players;
+ tdesc->pwszSessionName = sdesc->name_ofs ? (LPVOID)(pk + sdesc->name_ofs) : NULL;
+ tdesc->pwszPassword = sdesc->pass_ofs ? (LPVOID)(pk + sdesc->pass_ofs) : NULL;
+ tdesc->pvReservedData = sdesc->res_ofs ? (LPVOID)(pk + sdesc->res_ofs) : NULL;
+ tdesc->dwReservedDataSize = sdesc->res_size;
+ tdesc->pvApplicationReservedData = sdesc->appres_ofs ? (LPVOID)(pk + sdesc->appres_ofs) : NULL;
+ tdesc->dwApplicationReservedDataSize = sdesc->appres_size;
+ return sdesc->name_size + sdesc->pass_size + sdesc->res_size + sdesc->appres_size;
+}
+
+static int DPNET_SizeAppDesc(DirectPlay8GlobalData *dp8gdData, DPN_APPLICATION_DESC *sdesc)
+{
+ int sz = 0;
+ if (sdesc->pwszSessionName)
+ sz += (strlenW(sdesc->pwszSessionName)+1)*sizeof(WCHAR);
+ if (sdesc->pwszPassword)
+ sz += (strlenW(sdesc->pwszPassword)+1)*sizeof(WCHAR);
+ sz += sdesc->dwReservedDataSize;
+ sz += sdesc->dwApplicationReservedDataSize;
+ return sz;
+}
+
+static LPBYTE DPNET_FormatAppDesc(DirectPlay8GlobalData *dp8gdData, DP8_AppDesc *tdesc, DPN_APPLICATION_DESC *sdesc, LPVOID dst, LPVOID end)
+{
+ LPBYTE pk = dst;
+ LPBYTE ptr = end;
+ memset(tdesc, 0, sizeof(*tdesc));
+ tdesc->size = sizeof(*tdesc);
+ tdesc->flags = sdesc->dwFlags;
+ memcpy(&tdesc->instGUID, &sdesc->guidInstance, sizeof(GUID));
+ memcpy(&tdesc->appGUID, &sdesc->guidApplication, sizeof(GUID));
+ tdesc->max_players = sdesc->dwMaxPlayers;
+ tdesc->cur_players = sdesc->dwCurrentPlayers;
+ if (sdesc->pwszSessionName) {
+ DWORD len = (strlenW(sdesc->pwszSessionName)+1)*sizeof(WCHAR);
+ memcpy(ptr, sdesc->pwszSessionName, len);
+ tdesc->name_ofs = ptr - pk;
+ tdesc->name_size = len;
+ ptr += len;
+ }
+ if (sdesc->pwszPassword) {
+ DWORD len = (strlenW(sdesc->pwszPassword)+1)*sizeof(WCHAR);
+ memcpy(ptr, sdesc->pwszPassword, len);
+ tdesc->pass_ofs = ptr - pk;
+ tdesc->pass_size = len;
+ ptr += len;
+ }
+ if (sdesc->dwReservedDataSize) {
+ DWORD len = sdesc->dwReservedDataSize;
+ memcpy(ptr, sdesc->pvReservedData, len);
+ tdesc->res_ofs = ptr - pk;
+ tdesc->res_size = len;
+ ptr += len;
+ }
+ if (sdesc->dwApplicationReservedDataSize) {
+ DWORD len = sdesc->dwApplicationReservedDataSize;
+ memcpy(ptr, sdesc->pvApplicationReservedData, len);
+ tdesc->res_ofs = ptr - pk;
+ tdesc->res_size = len;
+ ptr += len;
+ }
+ return ptr;
+}
+
+static HRESULT DPNET_SendEnumResponse(DirectPlay8GlobalData *dp8gdData, IDirectPlay8Address *pAddr, WORD id, GUID* guidApp,
+ PVOID pvResponseData, DWORD dwResponseDataSize, PVOID pvResponseContext)
+{
+ DPNET_AsyncOp *aop;
+ DP8_EnumResponse *msg;
+ LPBYTE ptr;
+ int sz;
+
+ TRACE("...\n");
+
+ EnterCriticalSection(&dp8gdData->cs_player);
+
+ sz = DPNET_SizeAppDesc(dp8gdData, &dp8gdData->appdesc);
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg) + sz);
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ aop->pvUserContext = pvResponseContext;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->tag = DP8SESS_TAG;
+ msg->command = DP8SESS_ENUM_RESPONSE;
+ msg->id = id;
+
+ ptr = DPNET_FormatAppDesc(dp8gdData, &msg->app_desc, &dp8gdData->appdesc, &msg->reply_ofs, msg+1);
+
+ if (pvResponseData && dwResponseDataSize) {
+ msg->reply_ofs = ptr - (LPBYTE)&msg->reply_ofs;
+ msg->reply_size = dwResponseDataSize;
+ aop->cUserBuffer++;
+ aop->UserBuffer[0].pBufferData = pvResponseData;
+ aop->UserBuffer[0].dwBufferSize = dwResponseDataSize;
+ }
+
+ aop->dwID = msg->id;
+ aop->forget = TRUE;
+
+ LeaveCriticalSection(&dp8gdData->cs_player);
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ /* FIXME: do this in StartAsync when it's done? */
+ DPNET_ReturnBufferToApp(dp8gdData, S_OK, pvResponseData, pvResponseContext);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendConnectResponse(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_Connect *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->command = DP8SESS_CONNECT;
+ msg->type = DP8SESS_CONN_RESPONSE;
+ msg->pkt = 0;
+ msg->ver = DP8SESS_DEFVER;
+ msg->id = play->conn_id;
+ msg->time = GetTickCount();
+
+ aop->dwID = msg->id;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendConnectAck(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_ConnAck *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->command = DP8SESS_ACKNOWLEDGE;
+ msg->type = DP8SESS_ACK_CONNECT;
+ msg->unknown_02 = 1;
+ msg->ver = play->ver;
+ msg->id = play->conn_id;
+ msg->time = GetTickCount();
+
+ aop->dwID = msg->id;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendPathTest(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_PathTest *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->tag = DP8SESS_TAG;
+ msg->command = DP8SESS_PATH_TEST;
+ msg->id = 0x2551;
+ msg->key1 = DPNET_Random(dp8gdData);
+ msg->key2 = DPNET_Random(dp8gdData) * 49;
+
+ aop->dwID = msg->key1;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendNoData(DirectPlay8GlobalData *dp8gdData, dpPlayer *play, BYTE type, WORD pkt)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_Data *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->command = DP8SESS_DATA_RELIABLE;
+ msg->type = type;
+ msg->next_out = play->next_out++;
+ msg->next_in = play->next_in;
+ play->ack_in = play->next_in;
+
+ aop->dwID = msg->next_out;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendDataAck(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_DataAck *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->command = DP8SESS_ACKNOWLEDGE;
+ msg->type = DP8SESS_ACK_DATA_RELIABLE;
+ msg->unknown_02 = 1;
+ msg->next_out = play->next_out;
+ msg->next_in = play->next_in;
+ play->ack_in = play->next_in;
+ msg->time = GetTickCount();
+
+ aop->dwID = msg->next_out;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendDataAck2(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_DataAck *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg) + sizeof(DWORD));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->command = DP8SESS_ACKNOWLEDGE;
+ msg->type = DP8SESS_ACK_DATA_RELIABLE;
+ msg->unknown_02 = 3;
+ msg->next_out = play->next_out;
+ msg->next_in = play->next_in;
+ play->ack_in = play->next_in;
+ msg->time = GetTickCount();
+ *(DWORD*)(msg+1) = 1;
+
+ aop->dwID = msg->next_out;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendPlayerConnect(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_PlayerConnect *msg;
+ dpPlayer *lplay = &dp8gdData->localPlayer;
+ LPBYTE pk, ptr;
+ DWORD name_len;
+
+ TRACE("...\n");
+
+ DPNET_LockPlayer(dp8gdData, lplay);
+
+ name_len = lplay->name ? (strlenW(lplay->name)+1)*sizeof(WCHAR) : 0;
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg) +
+ lplay->conn_data_len + name_len + lplay->data_len);
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->msg.command = DP8SESS_MESSAGE;
+ msg->msg.type = 0;
+ msg->msg.next_out = play->next_out++;
+ msg->msg.next_in = play->next_in;
+ play->ack_in = msg->msg.next_in;
+ msg->msg.msg = DP8SESS_MSG_PLAYER_CONNECT;
+
+ pk = (LPBYTE)msg + sizeof(msg->msg);
+
+ msg->flags = DP8SESS_CONNF_PEER;
+ msg->dplay_ver = 7;
+ memcpy(&msg->instGUID, &dp8gdData->appdesc.guidInstance, sizeof(GUID));
+ memcpy(&msg->appGUID, &dp8gdData->appdesc.guidApplication, sizeof(GUID));
+
+ ptr = (LPBYTE)(msg+1);
+
+ /* FIXME: add address */
+ /* FIXME: add password */
+ /* FIXME: add url */
+
+ /* connect data */
+ if (lplay->conn_data_len) {
+ msg->conn_ofs = ptr - pk;
+ msg->conn_size = lplay->conn_data_len;
+ memcpy(ptr, lplay->conn_data, lplay->conn_data_len);
+ ptr += lplay->conn_data_len;
+ }
+
+ /* name */
+ if (lplay->name) {
+ msg->name_ofs = ptr - pk;
+ msg->name_size = name_len;
+ memcpy(ptr, lplay->name, name_len);
+ ptr += name_len;
+ }
+
+ /* player data */
+ if (lplay->data_len) {
+ msg->data_ofs = ptr - pk;
+ msg->data_size = lplay->data_len;
+ memcpy(ptr, lplay->conn_data, lplay->data_len);
+ ptr += lplay->data_len;
+ }
+
+ aop->dwID = msg->msg.next_out;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ DPNET_UnlockPlayer(dp8gdData, lplay);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendSessionInfo(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_SessionInfo *msg;
+ DP8_PlayerInfo *pi;
+ dpPlayer *cplay;
+ DWORD players;
+ LPBYTE pk, ptr;
+ int sz;
+
+ TRACE("...\n");
+
+ EnterCriticalSection(&dp8gdData->cs_player);
+
+ sz = sizeof(*msg);
+ sz += DPNET_SizeAppDesc(dp8gdData, &dp8gdData->appdesc);
+ sz += play->conn_data_len;
+
+ /* count players */
+ players = 0;
+ cplay = &dp8gdData->localPlayer;
+ players++;
+ sz += sizeof(DP8_PlayerInfo);
+ if (cplay->name)
+ sz += (strlenW(cplay->name)+1)*sizeof(WCHAR);
+ if (cplay->data)
+ sz += cplay->data_len;
+ /* don't attach URL to ourselves */
+ cplay = dp8gdData->remotePlayers;
+ while (cplay) {
+ if (cplay->status == PLAYER_ACCEPTED ||
+ cplay->status == PLAYER_ACTIVE) {
+ DWORD url_len = 0;
+ players++;
+ sz += sizeof(DP8_PlayerInfo);
+ IDirectPlay8Address_GetURLA(cplay->pAddress, NULL, &url_len);
+ sz += url_len;
+ if (cplay->name)
+ sz += (strlenW(cplay->name)+1)*sizeof(WCHAR);
+ if (cplay->data)
+ sz += cplay->data_len;
+ }
+ cplay = cplay->next;
+ }
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sz);
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->msg.command = DP8SESS_MESSAGE;
+ msg->msg.type = 0;
+ msg->msg.next_out = play->next_out++;
+ msg->msg.next_in = play->next_in;
+ play->ack_in = msg->msg.next_in;
+ msg->msg.msg = DP8SESS_MSG_SESSION_INFO;
+
+ pk = (LPBYTE)msg + sizeof(msg->msg);
+
+ msg->player_id = play->dwPlayerID;
+ msg->ver = 3;
+
+ msg->entries = players;
+
+ pi = (LPVOID)(msg+1);
+
+ ptr = (LPVOID)(pi+players);
+
+ /* players */
+ cplay = &dp8gdData->localPlayer;
+ pi->group_id = cplay->dwPlayerID;
+ pi->flags = DP8SESS_PINFOF_PEER;
+ if (dp8gdData->is_host)
+ pi->flags |= DP8SESS_PINFOF_HOST;
+ pi->ver = 2;
+ pi->dplay_ver = cplay->dplay_ver;
+ if (cplay->name) {
+ DWORD len = (strlenW(cplay->name)+1)*sizeof(WCHAR);
+ pi->name_ofs = ptr - pk;
+ pi->name_size = len;
+ memcpy(ptr, cplay->name, len);
+ ptr += len;
+ }
+ if (cplay->data) {
+ pi->data_ofs = ptr - pk;
+ pi->data_size = cplay->data_len;
+ memcpy(ptr, cplay->data, cplay->data_len);
+ ptr += cplay->data_len;
+ }
+ pi++;
+
+ cplay = dp8gdData->remotePlayers;
+ while (cplay) {
+ if (cplay->status == PLAYER_ACCEPTED ||
+ cplay->status == PLAYER_ACTIVE) {
+ DWORD url_len = sz - (ptr - (LPBYTE)msg);
+
+ pi->group_id = cplay->dwPlayerID;
+ pi->flags = DP8SESS_PINFOF_PEER;
+ if (cplay == dp8gdData->remoteHost)
+ pi->flags |= DP8SESS_PINFOF_HOST;
+ pi->ver = 2;
+ pi->dplay_ver = cplay->dplay_ver;
+
+ IDirectPlay8Address_GetURLA(cplay->pAddress, (LPVOID)ptr, &url_len);
+ pi->url_ofs = ptr - pk;
+ pi->url_size = url_len;
+ ptr += url_len;
+
+ if (cplay->name) {
+ DWORD len = (strlenW(cplay->name)+1)*sizeof(WCHAR);
+ pi->name_ofs = ptr - pk;
+ pi->name_size = len;
+ memcpy(ptr, cplay->name, len);
+ ptr += len;
+ }
+ if (cplay->data) {
+ pi->data_ofs = ptr - pk;
+ pi->data_size = cplay->data_len;
+ memcpy(ptr, cplay->data, cplay->data_len);
+ ptr += cplay->data_len;
+ }
+ pi++;
+ }
+ cplay = cplay->next;
+ }
+
+ ptr = DPNET_FormatAppDesc(dp8gdData, &msg->app_desc, &dp8gdData->appdesc, pk, ptr);
+
+ /* attach reply data from INDICATE_CONNECT */
+ if (play->conn_data_len) {
+ msg->reply_ofs = ptr - pk;
+ msg->reply_size = play->conn_data_len;
+ memcpy(ptr, play->conn_data, play->conn_data_len);
+ ptr += play->conn_data_len;
+ }
+
+ aop->dwID = msg->msg.next_out;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ LeaveCriticalSection(&dp8gdData->cs_player);
+
+ /* release reply data */
+ DPNET_ReturnBufferToApp(dp8gdData, S_OK, play->conn_data, play->conn_data_ctx);
+ play->conn_data = NULL;
+ play->conn_data_len = 0;
+ play->conn_data_ctx = 0;
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendSessionAck(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_SessionAck *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->msg.command = DP8SESS_MESSAGE;
+ msg->msg.type = 0;
+ msg->msg.next_out = play->next_out++;
+ msg->msg.next_in = play->next_in;
+ play->ack_in = play->next_in;
+ msg->msg.msg = DP8SESS_MSG_SESSION_ACK;
+
+ aop->dwID = msg->msg.next_out;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendAppDescUpdate(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_AppDescUpdate *msg;
+ int sz;
+
+ TRACE("...\n");
+
+ EnterCriticalSection(&dp8gdData->cs_player);
+
+ sz = DPNET_SizeAppDesc(dp8gdData, &dp8gdData->appdesc);
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg) + sz);
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->msg.command = DP8SESS_MESSAGE;
+ msg->msg.type = 0;
+ msg->msg.next_out = play->next_out++;
+ msg->msg.next_in = play->next_in;
+ play->ack_in = play->next_in;
+ msg->msg.msg = DP8SESS_MSG_APPDESC_UPDATE;
+
+ DPNET_FormatAppDesc(dp8gdData, &msg->app_desc, &dp8gdData->appdesc, &msg->app_desc, msg+1);
+
+ aop->dwID = msg->msg.next_out;
+ aop->forget = TRUE;
+
+ LeaveCriticalSection(&dp8gdData->cs_player);
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendPeerConnect(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_PeerConnect *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->msg.command = DP8SESS_MESSAGE;
+ msg->msg.type = 0;
+ msg->msg.next_out = play->next_out++;
+ msg->msg.next_in = play->next_in;
+ play->ack_in = play->next_in;
+ msg->msg.msg = DP8SESS_MSG_PEER_CONNECT;
+ msg->player_id = play->dwPlayerID;
+ msg->ver = 4;
+
+ aop->dwID = msg->msg.next_out;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static HRESULT DPNET_SendTableVer(DirectPlay8GlobalData *dp8gdData, dpPlayer *play)
+{
+ IDirectPlay8Address *pAddr = play->pAddress;
+ DPNET_AsyncOp *aop;
+ DP8_TableVer *msg;
+
+ TRACE("...\n");
+
+ aop = DPNET_AsyncAlloc(dp8gdData, 0, sizeof(*msg));
+ aop->dwType = 0;
+ aop->dwFlags = 0;
+ IDirectPlay8Address_AddRef(pAddr);
+ aop->pAddrHost = pAddr;
+ aop->pAddrDev = NULL; /* FIXME */
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->msg.command = DP8SESS_MESSAGE;
+ msg->msg.type = 0;
+ msg->msg.next_out = play->next_out++;
+ msg->msg.next_in = play->next_in;
+ play->ack_in = play->next_in;
+ msg->msg.msg = DP8SESS_MSG_TABLE_VER;
+ msg->ver = 4;
+
+ aop->dwID = msg->msg.next_out;
+ aop->forget = TRUE;
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ return S_OK;
+}
+
+static BOOL DPNET_ParseSessionInfo(DirectPlay8GlobalData *dp8gdData, void *pk, int pklen, dpPlayer *play)
+{
+ DP8_SessionInfo *msg = pk;
+ DP8_PlayerInfo *pi;
+ DPN_APPLICATION_DESC desc;
+ dpPlayer *cplay = &dp8gdData->localPlayer;
+ IDirectPlay8Address *pAddr = NULL;
+ HRESULT hr;
+ LPBYTE p;
+ DWORD c;
+
+ if (cplay->status != PLAYER_CONNECTED) {
+ TRACE("skipping!\n");
+ return FALSE;
+ }
+
+ play->status = PLAYER_ACCEPTED;
+ cplay->status = PLAYER_ACCEPTED;
+
+ hr = DPNET_CreateDirectPlay8Address(NULL, &IID_IDirectPlay8Address, (LPVOID *)&pAddr);
+
+ DPNET_ParseAppDesc(dp8gdData, &desc, &msg->app_desc, &msg->reply_ofs);
+
+ EnterCriticalSection(&dp8gdData->cs_player);
+
+ memcpy(&dp8gdData->appdesc.guidInstance, &desc.guidInstance, sizeof(GUID));
+ memcpy(&dp8gdData->appdesc.guidApplication, &desc.guidApplication, sizeof(GUID));
+ DPNET_SetAppDesc(dp8gdData, &desc);
+
+ p = (LPBYTE)msg + sizeof(msg->msg);
+
+ /* players */
+ pi = (LPVOID)(msg+1);
+ for (c=0; c<msg->entries; c++) {
+ BOOL was_new = FALSE;
+ dpPlayer *nplay;
+ nplay = DPNET_FindPlayerByID(dp8gdData, pi->group_id);
+ if (!nplay) {
+ /* not previously identified player */
+ was_new = TRUE;
+ if (pi->group_id == msg->player_id) {
+ /* it's us */
+ nplay = &dp8gdData->localPlayer;
+ nplay->dwPlayerID = msg->player_id;
+ } else
+ if (pi->url_size) {
+ /* it's a new player */
+ BOOL found;
+ IDirectPlay8Address_BuildFromURLA(pAddr, (LPVOID)(p + pi->url_ofs));
+ nplay = DPNET_MakePlayer(dp8gdData, pAddr, &found);
+ nplay->status = PLAYER_ACCEPTED;
+ } else {
+ /* it's our host */
+ nplay = dp8gdData->remoteHost;
+ nplay->dwPlayerID = pi->group_id;
+ }
+ }
+
+ nplay->dplay_ver = pi->dplay_ver;
+ if (nplay->name) {
+ HeapFree(GetProcessHeap(), 0, nplay->name);
+ nplay->name = NULL;
+ }
+ if (nplay->data) {
+ HeapFree(GetProcessHeap(), 0, nplay->data);
+ nplay->data = NULL;
+ nplay->data_len = 0;
+ }
+ if (pi->name_size) {
+ nplay->name = HeapAlloc(GetProcessHeap(), 0, pi->name_size);
+ memcpy(nplay->name, p + pi->name_ofs, pi->name_size);
+ }
+ if (pi->data_size) {
+ nplay->data = HeapAlloc(GetProcessHeap(), 0, pi->data_size);
+ memcpy(nplay->data, p + pi->data_ofs, pi->data_size);
+ }
+
+ if (was_new) {
+ DPNMSG_CREATE_PLAYER resp;
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.dpnidPlayer = nplay->dwPlayerID;
+ resp.pvPlayerContext = nplay->pvPlayerContext;
+ TRACE("dispatching Player Creation\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp);
+ TRACE("returned 0x%08x\n", hr);
+ nplay->pvPlayerContext = resp.pvPlayerContext;
+ if (nplay != &dp8gdData->localPlayer) {
+ nplay->status = PLAYER_ACTIVE;
+ dp8gdData->appdesc.dwCurrentPlayers++;
+ }
+ }
+
+ pi++;
+ }
+
+ /* grab connection reply data */
+ if (play->reply_data) {
+ HeapFree(GetProcessHeap(), 0, play->reply_data);
+ play->reply_data = NULL;
+ play->reply_data_len = 0;
+ }
+ if (msg->reply_size) {
+ play->reply_data = HeapAlloc(GetProcessHeap(), 0, msg->reply_size);
+ memcpy(play->reply_data, p + msg->reply_ofs, msg->reply_size);
+ }
+
+ LeaveCriticalSection(&dp8gdData->cs_player);
+
+ IDirectPlay8Address_Release(pAddr);
+
+ return TRUE;
+}
+
+static void DPNET_RecvMessage(DirectPlay8GlobalData *dp8gdData, void *pk, int pklen, dpPlayer *play)
+{
+ DP8_Message *pm = pk;
+ LPBYTE hdr = (LPVOID)(pm+1);
+ DPNET_AsyncOp *aop = NULL;
+ HRESULT hr;
+
+ switch (pm->msg) {
+ case DP8SESS_MSG_PLAYER_CONNECT:
+ if (dp8gdData->is_host) {
+ DP8_PlayerConnect *msg = pk;
+
+ DPNET_LockPlayer(dp8gdData, play);
+ if (play->status == PLAYER_CONNECTED) {
+ DPNMSG_INDICATE_CONNECT resp;
+
+ play->dplay_ver = msg->dplay_ver;
+ /* FIXME: verify flags? */
+ /* FIXME: verify password? */
+ /* FIXME: verify GUIDs? */
+ /* FIXME: grab address? */
+
+ if (msg->name_size) {
+ play->name = HeapAlloc(GetProcessHeap(), 0, msg->name_size);
+ memcpy(play->name, (LPVOID)(hdr + msg->name_ofs), msg->name_size);
+ TRACE("player name: %s\n", debugstr_w(play->name));
+ }
+
+ if (msg->data_size) {
+ play->data = HeapAlloc(GetProcessHeap(), 0, msg->data_size);
+ memcpy(play->name, (LPVOID)(hdr + msg->data_ofs), msg->data_size);
+ play->data_len = msg->data_size;
+ }
+
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.pAddressPlayer = play->pAddress;
+ resp.pAddressDevice = NULL; /* FIXME */
+ TRACE("connect data size: %d\n", msg->conn_size);
+ if (msg->conn_size) {
+ resp.pvUserConnectData = (LPVOID)(hdr + msg->conn_ofs);
+ resp.dwUserConnectDataSize = msg->conn_size;
+ }
+ TRACE("dispatching Connect indication\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_INDICATE_CONNECT, &resp);
+ TRACE("returned 0x%08x\n", hr);
+ if (hr != DPN_OK) {
+ /* connection rejected */
+ play->status = PLAYER_REJECTED;
+ DPNET_UnlockPlayer(dp8gdData, play);
+ /* FIXME: send reject response */
+ break;
+ }
+ /* player accepted, allocate ID and stuff */
+ play->dwPlayerID = InterlockedExchangeAdd(&dp8gdData->player_id, 1);
+ play->pvPlayerContext = resp.pvPlayerContext;
+ play->status = PLAYER_ACCEPTED;
+ play->conn_data = resp.pvReplyData;
+ play->conn_data_len = resp.dwReplyDataSize;
+ play->conn_data_ctx = resp.pvReplyContext;
+ DPNET_SendSessionInfo(dp8gdData, play);
+ }
+ DPNET_UnlockPlayer(dp8gdData, play);
+ break;
+ }
+ TRACE("ignoring player message since we're not hosting\n");
+ break;
+ case DP8SESS_MSG_SESSION_INFO:
+ if (!dp8gdData->is_host && play == dp8gdData->remoteHost) {
+ if (!DPNET_ParseSessionInfo(dp8gdData, pk, pklen, play))
+ break;
+
+ DPNET_SendSessionAck(dp8gdData, play);
+ DPNET_SendPathTest(dp8gdData, play);
+ break;
+ }
+ TRACE("ignoring session info message since it's not from host\n");
+ break;
+ case DP8SESS_MSG_SESSION_ACK:
+ if (dp8gdData->is_host) {
+ /* FIXME: Windows's appdesc packet contains the updated number of players
+ * (including the connecting one) */
+
+ /* DPNET_SendAppDescUpdate(dp8gdData, play); */
+ DPNET_SendPeerConnect(dp8gdData, play);
+ }
+ break;
+ case DP8SESS_MSG_PEER_CONNECT:
+ if (!dp8gdData->is_host) {
+ /* FIXME: what else to do here? */
+
+ DPNET_SendTableVer(dp8gdData, play);
+
+ /* FIXME: when exactly are we fully connected?
+ * Well, this seems close enough for now, I think. */
+ if (dp8gdData->localPlayer.status == PLAYER_ACCEPTED) {
+ DPNMSG_CONNECT_COMPLETE resp;
+
+ aop = DPNET_AsyncSearch(dp8gdData, DPN_MSGID_CONNECT_COMPLETE, 0);
+
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ if (aop) {
+ resp.hAsyncOp = (DPNHANDLE)aop;
+ resp.pvUserContext = aop->pvUserContext;
+ }
+ resp.hResultCode = S_OK;
+ resp.dpnidLocal = dp8gdData->localPlayer.dwPlayerID;
+ resp.pvApplicationReplyData = play->reply_data;
+ resp.dwApplicationReplyDataSize = play->reply_data_len;
+ TRACE("dispatching Connect completion\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CONNECT_COMPLETE, &resp);
+ TRACE("returned 0x%08x\n", hr);
+ dp8gdData->localPlayer.status = PLAYER_ACTIVE;
+ dp8gdData->appdesc.dwCurrentPlayers++;
+
+ if (aop) {
+ DPNET_AsyncRemove(dp8gdData, aop);
+ DPNET_AsyncSignal(dp8gdData, aop);
+ }
+ }
+ }
+ break;
+ case DP8SESS_MSG_TABLE_VER:
+ if (dp8gdData->is_host) {
+ /* FIXME: when exactly is the player fully connected?
+ * Well, this seems close enough for now, I think;
+ * it's supposed to connected to the other peers and stuff,
+ * but that's not implemented yet */
+ DPNET_LockPlayer(dp8gdData, play);
+ if (play->status == PLAYER_ACCEPTED) {
+ DPNMSG_CREATE_PLAYER resp;
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.dpnidPlayer = play->dwPlayerID;
+ resp.pvPlayerContext = play->pvPlayerContext;
+ TRACE("dispatching Player Creation\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp);
+ TRACE("returned 0x%08x\n", hr);
+ play->pvPlayerContext = resp.pvPlayerContext;
+ play->status = PLAYER_ACTIVE;
+ /* DPNET_SendNoData(dp8gdData, play, 0x0, 0x0); */
+ }
+ DPNET_SendDataAck(dp8gdData, play);
+ DPNET_UnlockPlayer(dp8gdData, play);
+ }
+ break;
+ default:
+ TRACE("unknown packet, but acknowledging anyway\n");
+ DPNET_SendDataAck(dp8gdData, play);
+ }
+}
+
+static BOOL DPNET_RecvData(DirectPlay8GlobalData *dp8gdData, void *pk, int pklen, dpPlayer *play, DWORD flags, DPNHANDLE buf)
+{
+ DPNMSG_RECEIVE resp;
+ HRESULT hr;
+
+ if (!pklen) return FALSE;
+
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.dpnidSender = play->dwPlayerID;
+ resp.pvPlayerContext = play->pvPlayerContext;
+ resp.pReceiveData = pk;
+ resp.dwReceiveDataSize = pklen;
+ resp.hBufferHandle = buf;
+ resp.dwReceiveFlags = flags;
+ TRACE("dispatching Receive (ptr %p, len %d)\n", pk, pklen);
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_RECEIVE, &resp);
+ TRACE("returned 0x%08x\n", hr);
+ return (hr == DPNSUCCESS_PENDING);
+}
+
+static BOOL DPNET_RecvPacket(DirectPlay8GlobalData *dp8gdData, void *pk, int pklen, IDirectPlay8Address *pAddr)
+{
+ LPBYTE hdr = pk;
+ DPNET_AsyncOp *aop = NULL;
+ HRESULT hr;
+ BOOL keep = FALSE;
+
+ debug_hexdump(pk, pklen);
+
+ if (pklen >= 2 && hdr[0] == DP8SESS_TAG) {
+ switch (hdr[1]) {
+ case DP8SESS_ENUM_REQUEST:
+ if (dp8gdData->is_host) {
+ DP8_EnumRequest *msg = pk;
+ GUID *guidApp = NULL;
+ int sz = sizeof(*msg);
+ if (msg->type == DP8SESS_ENUM_REQ_WITH_GUID) { guidApp = (LPVOID)(msg+1); sz += sizeof(GUID); }
+ if ((!guidApp) || IsEqualGUID(guidApp, &dp8gdData->appdesc.guidApplication)) {
+ DPNMSG_ENUM_HOSTS_QUERY resp;
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.pAddressSender = pAddr;
+ resp.pAddressDevice = NULL; /* FIXME */
+ if (pklen > sz) {
+ resp.pvReceivedData = (LPVOID)(hdr + sz);
+ resp.dwReceivedDataSize = pklen - sz;
+ }
+ resp.dwMaxResponseDataSize = 0; /* FIXME */
+ TRACE("dispatching EnumHosts query\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_ENUM_HOSTS_QUERY, &resp);
+ TRACE("returned 0x%08x\n", hr);
+ if (hr != DPN_OK) break;
+ hr = DPNET_SendEnumResponse(dp8gdData, pAddr, msg->id, guidApp,
+ resp.pvResponseData, resp.dwResponseDataSize,
+ resp.pvResponseContext);
+ break;
+ }
+ }
+ /* we should probably send some reject packet? */
+ TRACE("ignoring enum request since we're not hosting\n");
+ break;
+ case DP8SESS_ENUM_RESPONSE:
+ {
+ DP8_EnumResponse *msg = pk;
+ DPNMSG_ENUM_HOSTS_RESPONSE resp;
+ DPN_APPLICATION_DESC desc;
+
+ aop = DPNET_AsyncSearch(dp8gdData, DPN_MSGID_ENUM_HOSTS_RESPONSE, msg->id);
+ if (!aop) break;
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.pAddressSender = pAddr;
+ resp.pAddressDevice = aop->pAddrDev;
+ resp.pApplicationDescription = &desc;
+ resp.pvUserContext = aop->pvUserContext;
+ DPNET_ParseAppDesc(dp8gdData, &desc, &msg->app_desc, &msg->reply_ofs) + sizeof(*msg);
+ TRACE("session name: %s\n", debugstr_w(desc.pwszSessionName));
+ TRACE("max players: %d, cur players: %d\n", desc.dwMaxPlayers, desc.dwCurrentPlayers);
+ if (msg->reply_size) {
+ resp.pvResponseData = ((LPBYTE)&msg->reply_ofs) + msg->reply_ofs;
+ resp.dwResponseDataSize = msg->reply_size;
+ }
+ TRACE("dispatching EnumHosts response\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_ENUM_HOSTS_RESPONSE, &resp);
+ TRACE("returned 0x%08x\n", hr);
+ }
+ /* for now, we're going to assume that's it. */
+ DPNET_AsyncRemove(dp8gdData, aop);
+ DPNET_AsyncSignal(dp8gdData, aop);
+ break;
+ default:
+ TRACE("unknown session packet 0 %d\n", hdr[1]);
+ }
+ }
+ else if (pklen >= 2) {
+ switch (hdr[0]) {
+ case DP8SESS_CONNECT:
+ {
+ DP8_Connect *msg = pk;
+ switch (msg->type) {
+ case DP8SESS_CONN_REQUEST:
+ if (dp8gdData->is_host) {
+ BOOL found;
+ dpPlayer *play = DPNET_MakePlayer(dp8gdData, pAddr, &found);
+
+ DPNET_LockPlayer(dp8gdData, play);
+ if (!found) {
+ play->conn_id = msg->id;
+ play->ver = DP8SESS_MINVER(msg->ver, DP8SESS_DEFVER);
+ play->status = PLAYER_RESPONSE_SENT;
+ DPNET_SendConnectResponse(dp8gdData, play);
+ }
+ else if (play->status == PLAYER_RESPONSE_SENT) {
+ /* in case the first response was lost */
+ DPNET_SendConnectResponse(dp8gdData, play);
+ }
+ DPNET_UnlockPlayer(dp8gdData, play);
+ break;
+ }
+ /* we should probably send some reject packet? */
+ TRACE("ignoring connect request since we're not hosting\n");
+ break;
+ case DP8SESS_CONN_RESPONSE:
+ {
+ dpPlayer *play = DPNET_FindPlayerByAddr(dp8gdData, pAddr);
+
+ if (!play) {
+ TRACE("couldn't find connecting player\n");
+ break;
+ }
+
+ DPNET_LockPlayer(dp8gdData, play);
+ if (play->status == PLAYER_REQUEST_SENT) {
+ play->ver = DP8SESS_MINVER(msg->ver, DP8SESS_DEFVER);
+ play->status = PLAYER_CONNECTED;
+ TRACE("connected (ver %08x)\n", play->ver);
+
+ DPNET_SendConnectAck(dp8gdData, play);
+
+ if (play == dp8gdData->remoteHost) {
+ dp8gdData->localPlayer.status = PLAYER_CONNECTED;
+ DPNET_SendPlayerConnect(dp8gdData, play);
+ }
+
+ /* DPNET_SendNoData(dp8gdData, play, 0x0, 0x0); */
+ }
+ DPNET_UnlockPlayer(dp8gdData, play);
+ }
+ break;
+ default:
+ TRACE("unknown connect packet %d\n", msg->type);
+ }
+ }
+ break;
+ case DP8SESS_ACKNOWLEDGE:
+ {
+ DP8_ConnAck *msg = pk;
+ dpPlayer *play = DPNET_FindPlayerByAddr(dp8gdData, pAddr);
+
+ if (!play) {
+ TRACE("couldn't find acknowledging player\n");
+ break;
+ }
+
+ switch (msg->type) {
+ case DP8SESS_ACK_CONNECT:
+ {
+ DPNET_LockPlayer(dp8gdData, play);
+ if (play->status == PLAYER_RESPONSE_SENT) {
+ TRACE("connected (ver %08x)\n", play->ver);
+ play->ver = msg->ver;
+ play->status = PLAYER_CONNECTED;
+ /* DPNET_SendNoData(dp8gdData, play, 0x0, 0x0); */
+ }
+ DPNET_UnlockPlayer(dp8gdData, play);
+ }
+ break;
+ case DP8SESS_ACK_DATA_RELIABLE:
+ /* FIXME */
+ break;
+ default:
+ TRACE("unknown acknowledge packet %d\n", msg->type);
+ }
+ }
+ break;
+ case DP8SESS_MESSAGE:
+ {
+ DP8_Message *msg = pk;
+ dpPlayer *play = DPNET_FindPlayerByAddr(dp8gdData, pAddr);
+
+ if (!play) {
+ TRACE("couldn't find messaging player\n");
+ break;
+ }
+
+ DPNET_LockPlayer(dp8gdData, play);
+
+ if (!DPNET_GotAck(dp8gdData, play, msg->next_out, msg->next_in)) {
+ TRACE("ignoring packet due to bad sequence\n");
+ DPNET_UnlockPlayer(dp8gdData, play);
+ break;
+ }
+
+ play->next_in++;
+
+ DPNET_UnlockPlayer(dp8gdData, play);
+
+ DPNET_RecvMessage(dp8gdData, pk, pklen, play);
+ }
+ break;
+ case DP8SESS_DATA_RELIABLE:
+ {
+ DP8_Data *msg = pk;
+ dpPlayer *play = DPNET_FindPlayerByAddr(dp8gdData, pAddr);
+ DWORD flags = 0;
+
+ if (!play) {
+ TRACE("couldn't find messaging player\n");
+ break;
+ }
+
+ /* first empty data packet: */
+ /* 3f 00 00 00 */
+ /* acknowledge with: */
+ /* 80 06 01 00 01 01 00 00 <timestamp> */
+
+ /* new empty data packet: */
+ /* 3f 0a 02 02 */
+ /* acknowledge with: */
+ /* 80 06 03 00 02 01 00 00 <timestamp> 01 00 00 00 */
+
+ DPNET_LockPlayer(dp8gdData, play);
+
+ if (!DPNET_GotAck(dp8gdData, play, msg->next_out, msg->next_in)) {
+ TRACE("ignoring packet due to bad sequence\n");
+ DPNET_UnlockPlayer(dp8gdData, play);
+ break;
+ }
+
+ play->next_in++;
+
+ switch (msg->type) {
+ case 0x00:
+ DPNET_SendDataAck(dp8gdData, play);
+ flags |= DPNRECEIVE_GUARANTEED;
+ keep = DPNET_RecvData(dp8gdData, msg+1, pklen - sizeof(*msg), play, flags, (DPNHANDLE)pk);
+ break;
+ case 0x0a:
+ DPNET_SendDataAck2(dp8gdData, play);
+ keep = DPNET_RecvData(dp8gdData, msg+1, pklen - sizeof(*msg), play, flags, (DPNHANDLE)pk);
+ break;
+ }
+
+ DPNET_UnlockPlayer(dp8gdData, play);
+ }
+ break;
+ default:
+ TRACE("unknown session packet %d\n", hdr[0]);
+ }
+ }
+ return keep;
+}
+
+static HRESULT DPNET_SendPacket(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop)
+{
+ HRESULT hr;
+
+ DPNET_AsyncInsert(dp8gdData, aop);
+ /* FIXME: enter into appropriate-priority queue first,
+ * network buffers may be full and other packets may have priority. */
+ hr = IDirectPlay8ServiceProvider_SendTo(dp8gdData->sp, aop->pAddrHost,
+ &aop->PackBuffer, aop->cUserBuffer+1, 0);
+ if (hr == DPNERR_NOTREADY) {
+ /* once we've implemented queues, we should make the
+ * SP call us as soon as it's ready... (WSAEventSelect) */
+ TRACE("transmit buffers full, must try again later!\n");
+ }
+
+ /* FIXME: only dispatch this when sent to all destinations, I think */
+ if ((aop->dwType == DPN_MSGID_SEND_COMPLETE) &&
+ !(aop->dwFlags & (DPNSEND_COMPLETEONPROCESS|DPNSEND_NOCOMPLETE))) {
+ DPNMSG_SEND_COMPLETE resp;
+
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.hAsyncOp = (DPNHANDLE)aop;
+ resp.pvUserContext = aop->pvUserContext;
+ resp.hResultCode = hr;
+ resp.dwSendTime = GetTickCount() - aop->dwTimeSent;
+ resp.dwFirstFrameRTT = (DWORD)-1;
+ resp.dwFirstFrameRetryCount = (DWORD)-1;
+ resp.dwSendCompleteFlags = 0;
+ if (aop->dwFlags & DPNSEND_GUARANTEED)
+ resp.dwSendCompleteFlags |= DPNSENDCOMPLETE_GUARANTEED;
+ if (aop->cUserBuffer) {
+ resp.pBuffers = aop->UserBuffer;
+ resp.dwNumBuffers = aop->cUserBuffer;
+ }
+ TRACE("dispatching Send completion\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_SEND_COMPLETE, &resp);
+ TRACE("returned\n");
+ }
+
+ /* FIXME: should only remove if the transmit was successful */
+ if (aop->forget) {
+ DPNET_AsyncRemove(dp8gdData, aop);
+ DPNET_AsyncFree(dp8gdData, aop);
+ }
+ return S_OK;
+}
+
+static HRESULT DPNET_StartAsync(DirectPlay8GlobalData *dp8gdData, DPNET_AsyncOp *aop)
+{
+#ifdef FAKE_IT
+ HRESULT hr;
+ switch (aop->dwType) {
+ case DPN_MSGID_ENUM_HOSTS_RESPONSE:
+ {
+ static WCHAR sess_name[] = {'F','a','k','e',' ','S','e','s','s','i','o','n',0};
+ static WCHAR host_name[] = {'1','2','7','.','0','.','0','.','1',0};
+ DPNMSG_ENUM_HOSTS_RESPONSE resp;
+ DPN_APPLICATION_DESC desc;
+ IDirectPlay8AddressImpl *addrImpl = (IDirectPlay8AddressImpl *)aop->pAddrDev;
+ IDirectPlay8Address *addr = NULL;
+
+ DPNET_CreateDirectPlay8Address(NULL, &IID_IDirectPlay8Address, (LPVOID*)&addr);
+ IDirectPlay8Address_SetSP(addr, &addrImpl->guidSP);
+ IDirectPlay8Address_AddComponent(addr, DPNA_KEY_HOSTNAME, host_name, sizeof(host_name)/sizeof(WCHAR), DPNA_DATATYPE_STRING);
+
+ memset(&resp, 0, sizeof(resp));
+ memset(&desc, 0, sizeof(desc));
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+ resp.dwSize = sizeof(resp);
+ resp.pAddressSender = addr;
+ resp.pAddressDevice = aop->pAddrDev;
+ resp.pApplicationDescription = &desc;
+ resp.pvUserContext = aop->pvUserContext;
+ desc.dwSize = sizeof(desc);
+ memcpy(&desc.guidApplication, &dp8gdData->guidApplication, sizeof(GUID));
+ desc.pwszSessionName = sess_name;
+ TRACE("dispatching fake EnumHosts response\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, aop->dwType, &resp);
+ TRACE("returned\n");
+ IDirectPlay8Address_Release(addr);
+ }
+ break;
+ case DPN_MSGID_CONNECT_COMPLETE:
+ dp8gdData->localPlayer.dwPlayerID = 1;
+ {
+ DPNMSG_CONNECT_COMPLETE resp;
+
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.hAsyncOp = (DPNHANDLE)aop;
+ resp.pvUserContext = aop->pvUserContext;
+ resp.hResultCode = S_OK;
+ resp.dpnidLocal = dp8gdData->localPlayer.dwPlayerID;
+ TRACE("dispatching fake Connect response\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, aop->dwType, &resp);
+ TRACE("returned\n");
+ }
+ {
+ DPNMSG_CREATE_PLAYER resp;
+
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.dpnidPlayer = 2;
+ resp.pvPlayerContext = NULL;
+ TRACE("dispatching fake remote CreatePlayer message\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp);
+ dp8gdData->localPlayer.pvPlayerContext = resp.pvPlayerContext;
+ TRACE("returned\n");
+ }
+ {
+ DPNMSG_CREATE_PLAYER resp;
+
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.dpnidPlayer = dp8gdData->localPlayer.dwPlayerID;
+ resp.pvPlayerContext = dp8gdData->localPlayer.pvPlayerContext;
+ TRACE("dispatching fake local CreatePlayer message\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp);
+ dp8gdData->localPlayer.pvPlayerContext = resp.pvPlayerContext;
+ TRACE("returned\n");
+ }
+ break;
+ }
+ DPNET_AsyncSignal(dp8gdData, aop);
+#else
+ HRESULT hr;
+
+ hr = DPNET_SendPacket(dp8gdData, aop);
+ TRACE("transmit result: 0x%08x\n", hr);
+#endif
+
+ return S_OK;
+}
+
+HRESULT DPNET_GetCaps(DirectPlay8GlobalData *dp8gdData,
+ DPN_CAPS *const pdpCaps,
+ const DWORD dwFlags)
+{
+ DWORD size = min(pdpCaps->dwSize, sizeof(dp8gdData->dpnCaps));
+ memcpy(pdpCaps, &dp8gdData->dpnCaps, size);
+ return S_OK;
+}
+
+HRESULT DPNET_GetSPCaps(DirectPlay8GlobalData *dp8gdData,
+ const GUID *const pguidSP,
+ DPN_SP_CAPS *const pdpnSPCaps,
+ const DWORD dwFlags)
+{
+ HRESULT hr;
+ hr = DPNET_InitSP(dp8gdData, pguidSP);
+ if (FAILED(hr)) return hr;
+ hr = IDirectPlay8ServiceProvider_GetSPCaps(dp8gdData->sp, pdpnSPCaps, dwFlags);
+ return hr;
+}
+
+HRESULT DPNET_CancelAsyncOperation(DirectPlay8GlobalData *dp8gdData,
+ const DPNHANDLE hAsyncHandle,
+ const DWORD dwFlags)
+{
+ DPNET_AsyncOp *aop;
+
+ if (!dwFlags) {
+ aop = (DPNET_AsyncOp *)hAsyncHandle;
+#if 0
+ DPNET_AsyncRemove(dp8gdData, aop);
+ DPNET_AsyncSignal(dp8gdData, aop);
+#endif
+ }
+
+ return S_OK;
+}
+
+HRESULT DPNET_ReturnBuffer(DirectPlay8GlobalData *dp8gdData,
+ const DPNHANDLE hBufferHandle,
+ const DWORD dwFlags)
+{
+ HRESULT hr;
+ hr = IDirectPlay8ServiceProvider_ReturnBuffer(dp8gdData->sp, (void *)hBufferHandle, dwFlags);
+ return hr;
+}
+
+HRESULT DPNET_GetApplicationDesc(DirectPlay8GlobalData *dp8gdData,
+ DPN_APPLICATION_DESC *const pAppDescBuffer,
+ DWORD *const pcbDataSize,
+ const DWORD dwFlags)
+{
+ EnterCriticalSection(&dp8gdData->cs_player);
+
+ FIXME("return application desc\n");
+
+ LeaveCriticalSection(&dp8gdData->cs_player);
+
+ return S_OK;
+}
+
+HRESULT DPNET_SetPeerInfo(DirectPlay8GlobalData *dp8gdData,
+ const DPN_PLAYER_INFO *const pdpnPlayerInfo,
+ PVOID const pvAsyncContext, DPNHANDLE *const phAsyncHandle,
+ const DWORD dwFlags)
+{
+ dpPlayer *play = &dp8gdData->localPlayer;
+
+ if (play->status != PLAYER_UNKNOWN) {
+ FIXME("change local info\n");
+ return DPNSUCCESS_PENDING;
+ }
+
+ DPNET_LockPlayer(dp8gdData, play);
+
+ if (pdpnPlayerInfo->dwInfoFlags & DPNINFO_NAME) {
+ if (play->name) HeapFree(GetProcessHeap(), 0, play->name);
+ play->name = NULL;
+ if (pdpnPlayerInfo->pwszName) {
+ DWORD l = (strlenW(pdpnPlayerInfo->pwszName)+1)*sizeof(WCHAR);
+ play->name = HeapAlloc(GetProcessHeap(), 0, l);
+ memcpy(play->name, pdpnPlayerInfo->pwszName, l);
+ }
+ }
+
+ if (pdpnPlayerInfo->dwInfoFlags & DPNINFO_DATA) {
+ if (play->data) HeapFree(GetProcessHeap(), 0, play->data);
+ play->data = NULL;
+ play->data_len = 0;
+ if (pdpnPlayerInfo->pvData && pdpnPlayerInfo->dwDataSize) {
+ play->data = HeapAlloc(GetProcessHeap(), 0, pdpnPlayerInfo->dwDataSize);
+ play->data_len = pdpnPlayerInfo->dwDataSize;
+ memcpy(play->data, pdpnPlayerInfo->pvData, pdpnPlayerInfo->dwDataSize);
+ }
+ }
+
+ DPNET_UnlockPlayer(dp8gdData, play);
+
+ return S_OK;
+}
+
+HRESULT DPNET_GetPeerInfo(DirectPlay8GlobalData *dp8gdData,
+ const DPNID dpnid,
+ DPN_PLAYER_INFO *const pdpnPlayerInfo,
+ DWORD *const pdwSize,
+ const DWORD dwFlags)
+{
+ dpPlayer *play;
+ DWORD len;
+
+ play = DPNET_FindPlayerByID(dp8gdData, dpnid);
+ if (!play) {
+ TRACE("player not found\n");
+ return DPNERR_INVALIDPLAYER;
+ }
+
+ DPNET_LockPlayer(dp8gdData, play);
+
+ len = sizeof(DPN_PLAYER_INFO);
+ if (play->name)
+ len += (strlenW(play->name)+1)*sizeof(WCHAR);
+ if (play->data)
+ len += play->data_len;
+
+ if (*pdwSize < len) {
+ *pdwSize = len;
+ DPNET_UnlockPlayer(dp8gdData, play);
+ return DPNERR_BUFFERTOOSMALL;
+ }
+
+ if (pdpnPlayerInfo) {
+ LPBYTE ptr = (LPVOID)(pdpnPlayerInfo+1);
+ pdpnPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
+ pdpnPlayerInfo->dwInfoFlags = DPNINFO_NAME | DPNINFO_DATA;
+ pdpnPlayerInfo->dwPlayerFlags = 0;
+ if (play == &dp8gdData->localPlayer) {
+ pdpnPlayerInfo->dwPlayerFlags |= DPNPLAYER_LOCAL;
+ if (dp8gdData->is_host)
+ pdpnPlayerInfo->dwPlayerFlags |= DPNPLAYER_HOST;
+ }
+ if (play == dp8gdData->remoteHost)
+ pdpnPlayerInfo->dwPlayerFlags |= DPNPLAYER_HOST;
+ if (play->name) {
+ DWORD len = (strlenW(play->name)+1)*sizeof(WCHAR);
+ pdpnPlayerInfo->pwszName = (LPVOID)ptr;
+ memcpy(ptr, play->name, len);
+ ptr += len;
+ } else {
+ pdpnPlayerInfo->pwszName = NULL;
+ }
+ if (play->data) {
+ pdpnPlayerInfo->pvData = (LPVOID)ptr;
+ pdpnPlayerInfo->dwDataSize = play->data_len;
+ memcpy(ptr, play->data, play->data_len);
+ ptr += play->data_len;
+ } else {
+ pdpnPlayerInfo->pvData = NULL;
+ pdpnPlayerInfo->dwDataSize = 0;
+ }
+ }
+
+ DPNET_UnlockPlayer(dp8gdData, play);
+
+ return S_OK;
+}
+
+HRESULT DPNET_GetPlayerContext(DirectPlay8GlobalData *dp8gdData,
+ const DPNID dpnid,
+ PVOID *const ppvPlayerContext,
+ const DWORD dwFlags)
+{
+ dpPlayer *play;
+
+ play = DPNET_FindPlayerByID(dp8gdData, dpnid);
+ if (!play) {
+ TRACE("player not found\n");
+ return DPNERR_INVALIDPLAYER;
+ }
+
+ DPNET_LockPlayer(dp8gdData, play);
+
+ /* FIXME: make sure CREATE_PLAYER is complete,
+ * return DPNERR_NOTREADY if not */
+
+ *ppvPlayerContext = play->pvPlayerContext;
+
+ DPNET_UnlockPlayer(dp8gdData, play);
+
+ return S_OK;
+}
+
+HRESULT DPNET_EnumHosts(DirectPlay8GlobalData *dp8gdData,
+ PDPN_APPLICATION_DESC const pdnAppDesc,
+ IDirectPlay8Address *const pAddrHost, IDirectPlay8Address *const pDeviceInfo,
+ PVOID const pvUserEnumData, const DWORD dwUserEnumDataSize,
+ const DWORD dwEnumCount, const DWORD dwRetryInterval,
+ const DWORD dwTimeOut, PVOID const pvUserContext,
+ DPNHANDLE *const phAsyncHandle, const DWORD dwFlags)
+{
+ IDirectPlay8AddressImpl *addrImplDevice = (IDirectPlay8AddressImpl *)pDeviceInfo;
+ DPN_SP_CAPS dpnSPCaps;
+ DPNET_AsyncOp *aop;
+ DP8_EnumRequest *msg;
+ LPVOID msg_end;
+ BOOL has_guid;
+
+ TRACE(" app dwFlags: 0x%08x\n", pdnAppDesc->dwFlags);
+
+ DPNET_InitSP(dp8gdData, &addrImplDevice->guidSP);
+
+ has_guid = !IsEqualGUID(&GUID_NULL, &pdnAppDesc->guidApplication);
+
+ aop = DPNET_AsyncAlloc(dp8gdData, DPN_MSGID_ENUM_HOSTS_RESPONSE, sizeof(*msg) + has_guid*sizeof(GUID) + dwUserEnumDataSize);
+ aop->dwFlags = dwFlags;
+ aop->pvUserContext = pvUserContext;
+ if (pAddrHost) {
+ IDirectPlay8Address_AddRef(pAddrHost);
+ aop->pAddrHost = pAddrHost;
+ }
+ IDirectPlay8Address_AddRef(pDeviceInfo);
+ aop->pAddrDev = pDeviceInfo;
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->tag = DP8SESS_TAG;
+ msg->command = DP8SESS_ENUM_REQUEST;
+ msg->id = (DPNET_Random(dp8gdData) & 0xfff0) + 1;
+ msg->type = has_guid ? DP8SESS_ENUM_REQ_WITH_GUID : DP8SESS_ENUM_REQ_WITHOUT_GUID;
+ msg_end = msg+1;
+
+ if (has_guid) {
+ memcpy(msg_end, &pdnAppDesc->guidApplication, sizeof(GUID));
+ msg_end = ((GUID*)msg_end)+1;
+ }
+
+ if (dwUserEnumDataSize) {
+ /* just copy to end of packet for now */
+ memcpy(msg_end, pvUserEnumData, dwUserEnumDataSize);
+ }
+
+ aop->dwID = msg->id;
+
+ IDirectPlay8ServiceProvider_GetSPCaps(dp8gdData->sp, &dpnSPCaps, 0);
+ if (dwEnumCount)
+ aop->dwRetryLimit = dwEnumCount;
+ else
+ aop->dwRetryLimit = dpnSPCaps.dwDefaultEnumCount;
+
+ if (dwRetryInterval)
+ aop->dwRetryInterval = dwRetryInterval;
+ else
+ aop->dwRetryInterval = dpnSPCaps.dwDefaultEnumRetryInterval;
+
+ if (dwTimeOut)
+ aop->dwTimeOut = dwTimeOut;
+ else
+ aop->dwTimeOut = dpnSPCaps.dwDefaultEnumTimeout;
+
+ if (dwFlags & DPNENUMHOSTS_SYNC)
+ DPNET_AsyncSetSync(dp8gdData, aop);
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ if (dwFlags & DPNENUMHOSTS_SYNC) {
+ DPNET_AsyncWait(dp8gdData, aop);
+ return DPNET_AsyncFree(dp8gdData, aop);
+ } else {
+ *phAsyncHandle = (DPNHANDLE)aop;
+ }
+
+ return S_OK;
+}
+
+HRESULT DPNET_Connect(DirectPlay8GlobalData *dp8gdData,
+ const DPN_APPLICATION_DESC *const pdnAppDesc,
+ IDirectPlay8Address *pAddrHost,
+ IDirectPlay8Address *pDeviceInfo,
+ const DPN_SECURITY_DESC * const pdnSecurity,
+ const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
+ const void *const pvUserConnectData,
+ DWORD dwUserConnectDataSize,
+ void *pvPlayerContext, void *pvAsyncContext,
+ DPNHANDLE *phAsyncHandle, DWORD dwFlags)
+{
+ IDirectPlay8AddressImpl *addrImplDevice = (IDirectPlay8AddressImpl *)pDeviceInfo;
+ DPNET_AsyncOp *aop;
+ DP8_Connect *msg;
+ dpPlayer *play = &dp8gdData->localPlayer;
+ BOOL found;
+
+ TRACE(" app dwFlags: 0x%08x\n", pdnAppDesc->dwFlags);
+
+ DPNET_KillPlayers(dp8gdData);
+
+ DPNET_SetAppDesc(dp8gdData, pdnAppDesc);
+
+ DPNET_InitSP(dp8gdData, &addrImplDevice->guidSP);
+
+ if (pdnSecurity || pdnCredentials)
+ FIXME("we dont support security stuff right now\n");
+
+ dp8gdData->pkt_id = 0;
+
+ /* initialize local player */
+ play->status = PLAYER_REQUEST_SENT;
+ play->pvPlayerContext = pvPlayerContext;
+
+ if (dwUserConnectDataSize) {
+ play->conn_data = HeapAlloc(GetProcessHeap(), 0, dwUserConnectDataSize);
+ play->conn_data_len = dwUserConnectDataSize;
+ memcpy(play->conn_data, pvUserConnectData, dwUserConnectDataSize);
+ }
+
+ /* initialize remote player (host) */
+ play = DPNET_MakePlayer(dp8gdData, pAddrHost, &found);
+ dp8gdData->remoteHost = play;
+ play->status = PLAYER_REQUEST_SENT;
+ play->conn_id = DPNET_Random(dp8gdData);
+
+ aop = DPNET_AsyncAlloc(dp8gdData, DPN_MSGID_CONNECT_COMPLETE, sizeof(*msg));
+ aop->dwFlags = dwFlags;
+ aop->pvUserContext = pvAsyncContext;
+ if (pAddrHost) {
+ IDirectPlay8Address_AddRef(pAddrHost);
+ aop->pAddrHost = pAddrHost;
+ }
+ IDirectPlay8Address_AddRef(pDeviceInfo);
+ aop->pAddrDev = pDeviceInfo;
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ msg->command = DP8SESS_CONNECT;
+ msg->type = DP8SESS_CONN_REQUEST;
+ msg->pkt = 0;
+ msg->ver = DP8SESS_DEFVER;
+ msg->id = play->conn_id;
+ msg->time = GetTickCount();
+
+ aop->dwID = play->conn_id;
+
+ aop->dwRetryLimit = dp8gdData->dpnCaps.dwConnectRetries;
+ aop->dwRetryInterval = dp8gdData->dpnCaps.dwConnectTimeout;
+
+ if (dwFlags & DPNCONNECT_SYNC)
+ DPNET_AsyncSetSync(dp8gdData, aop);
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ if (dwFlags & DPNCONNECT_SYNC) {
+ DPNET_AsyncWait(dp8gdData, aop);
+ return DPNET_AsyncFree(dp8gdData, aop);
+ } else {
+ *phAsyncHandle = (DPNHANDLE)aop;
+ }
+
+ return DPNSUCCESS_PENDING;
+}
+
+HRESULT DPNET_Host(DirectPlay8GlobalData *dp8gdData,
+ const DPN_APPLICATION_DESC *const pdnAppDesc,
+ IDirectPlay8Address **const prgpDeviceInfo,
+ const DWORD cDeviceInfo,
+ const DPN_SECURITY_DESC * const pdnSecurity,
+ const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
+ void *pvPlayerContext,
+ const DWORD dwFlags)
+{
+ IDirectPlay8AddressImpl *addrImplDevice = (IDirectPlay8AddressImpl *)prgpDeviceInfo[0];
+ DPNMSG_CREATE_PLAYER resp;
+ dpPlayer *play = &dp8gdData->localPlayer;
+ HRESULT hr;
+
+ TRACE(" app dwFlags: 0x%08x\n", pdnAppDesc->dwFlags);
+
+ DPNET_KillPlayers(dp8gdData);
+
+ DPNET_SetAppDesc(dp8gdData, pdnAppDesc);
+
+ DPNET_InitSP(dp8gdData, &addrImplDevice->guidSP);
+
+ if (pdnSecurity || pdnCredentials)
+ FIXME("we dont support security stuff right now\n");
+
+ dp8gdData->pkt_id = 0;
+
+ dp8gdData->is_host = TRUE;
+
+ /* initialize local player (host) */
+ play->status = PLAYER_ACTIVE;
+ play->pvPlayerContext = pvPlayerContext;
+
+ play->dwPlayerID = 1; /* FIRST POST!!!11!one! */
+ dp8gdData->player_id = 2;
+ dp8gdData->appdesc.dwCurrentPlayers = 1;
+
+ memset(&resp, 0, sizeof(resp));
+ resp.dwSize = sizeof(resp);
+ resp.dpnidPlayer = play->dwPlayerID;
+ resp.pvPlayerContext = play->pvPlayerContext;
+ TRACE("dispatching local CreatePlayer message\n");
+ hr = dp8gdData->pfMessageHandler(dp8gdData->pvUserContext, DPN_MSGID_CREATE_PLAYER, &resp);
+ dp8gdData->localPlayer.pvPlayerContext = resp.pvPlayerContext;
+ TRACE("returned\n");
+
+ return S_OK;
+}
+
+/**** FIXME: move this and related stuff to a separate file (transport.c?) ****/
+
+HRESULT DPNET_SendTo(DirectPlay8GlobalData *dp8gdData, const DPNID dpnid,
+ const DPN_BUFFER_DESC *const pBufferDesc, const DWORD cBufferDesc,
+ const DWORD dwTimeOut, void *pvAsyncContext,
+ DPNHANDLE *const phAsyncHandle, const DWORD dwFlags)
+{
+ DPNET_AsyncOp *aop;
+ DP8_Data *msg;
+ dpPlayer *play = NULL;
+ DWORD c, len;
+
+ if (dpnid == DPNID_ALL_PLAYERS_GROUP) {
+ /* just sending to first player for now... */
+ play = dp8gdData->remotePlayers;
+ /* FIXME: to be able to send to more than one player
+ * and still only submit SEND_COMPLETE once, we'll
+ * probably need to change the AsyncOp structure. */
+
+ if (!(dwFlags & DPNSEND_NOLOOPBACK)) {
+ FIXME("dispatch loopback RECEIVE\n");
+ }
+
+ if (!play) {
+ /* we're alone, talking to ourselves */
+ FIXME("no receiver, should still dispatch SEND_COMPLETE\n");
+ return S_OK;
+ }
+ } else {
+ play = DPNET_FindPlayerByID(dp8gdData, dpnid);
+
+ if (!play) return DPNERR_INVALIDPLAYER;
+ }
+
+ len = 0;
+ for (c=0; c<cBufferDesc; c++)
+ len += pBufferDesc[c].dwBufferSize;
+
+ aop = DPNET_AsyncAlloc(dp8gdData, DPN_MSGID_SEND_COMPLETE, sizeof(*msg) + ((dwFlags & DPNSEND_NOCOPY) ? 0 : len));
+ aop->dwFlags = dwFlags;
+ aop->pvUserContext = (PVOID)pvAsyncContext;
+ if (play) {
+ IDirectPlay8Address_AddRef(play->pAddress);
+ aop->pAddrHost = play->pAddress;
+ }
+ aop->pAddrDev = NULL;
+
+ msg = (LPVOID)aop->PackBuffer.pBufferData;
+
+ DPNET_LockPlayer(dp8gdData, play);
+
+ msg->command = (dwFlags & DPNSEND_GUARANTEED) ? DP8SESS_DATA_RELIABLE : DP8SESS_DATA_UNRELIABLE;
+ msg->type = 0x0;
+ msg->next_out = play->next_out++;
+ msg->next_in = play->next_in;
+ play->ack_in = play->next_in;
+
+ aop->dwTimeOut = dwTimeOut;
+ aop->dwTimeSent = GetTickCount();
+
+ if (dwFlags & DPNSEND_NOCOPY) {
+ aop->cUserBuffer = cBufferDesc;
+ memcpy(&aop->UserBuffer, pBufferDesc, sizeof(DPN_BUFFER_DESC)*cBufferDesc);
+ } else {
+ LPBYTE pk = (LPVOID)(msg+1);
+ for (c=0; c<cBufferDesc; c++) {
+ memcpy(pk, pBufferDesc[c].pBufferData, pBufferDesc[c].dwBufferSize);
+ pk += pBufferDesc[c].dwBufferSize;
+ }
+ }
+
+ aop->dwID = msg->next_out;
+ aop->forget = TRUE; /* for now */
+
+ DPNET_UnlockPlayer(dp8gdData, play);
+
+ if (dwFlags & DPNCONNECT_SYNC)
+ DPNET_AsyncSetSync(dp8gdData, aop);
+
+ DPNET_StartAsync(dp8gdData, aop);
+
+ if (dwFlags & DPNCONNECT_SYNC) {
+ DPNET_AsyncWait(dp8gdData, aop);
+ return DPNET_AsyncFree(dp8gdData, aop);
+ } else {
+ *phAsyncHandle = (DPNHANDLE)aop;
+ }
+
+ return DPNSUCCESS_PENDING;
+}
diff --git a/dlls/dpnet/sp_tcpip.c b/dlls/dpnet/sp_tcpip.c
new file mode 100644
index 0000000..24158be
--- /dev/null
+++ b/dlls/dpnet/sp_tcpip.c
@@ -0,0 +1,613 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+#include "winsock2.h"
+#include "wine/unicode.h"
+
+#include "dplay8.h"
+#include "dplobby8.h"
+#include "dplay8_private.h"
+#include "dplay8sp.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+static ICOM_VTABLE(IDirectPlay8ServiceProvider) directPlay8SP_TCPIPVT;
+
+void SP_TCPIP_ReleaseAddressData(PVOID data)
+{
+ HeapFree(GetProcessHeap(), 0, data);
+}
+
+/* SHOULDNT NEED TO DUPLICATE. SHOULD USE URL */
+void SP_TCPIP_DuplicateAddressData(IDirectPlay8Address *pAddr, PVOID data)
+{
+ struct sockaddr_in *newData;
+
+ newData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sockaddr_in));
+
+ memcpy(newData, data, sizeof(struct sockaddr_in));
+ DPNET_Address_SetSPData(pAddr, newData, SP_TCPIP_ReleaseAddressData,
+ SP_TCPIP_DuplicateAddressData);
+}
+
+HRESULT WINAPI DirectPlay8SP_TCPIP_BuildAddressFromSPData(PDIRECTPLAY8SERVICEPROVIDER iface,
+ IDirectPlay8Address *pAddr,
+ PVOID pvSPData)
+{
+ /* ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); */
+ struct sockaddr_in *sin = pvSPData;
+ struct sockaddr_in *addrSPData;
+ char buf[16];
+ WCHAR wbuf[16];
+ DWORD port;
+
+ TRACE("(%p)->(%p, %p)\n", iface, pAddr, pvSPData);
+
+ /* FIXME: we could call IDirectPlay8AddressIP::BuildFromSockAddr,
+ * but it's not implemented yet */
+
+ /* FIXME: call getnameinfo() instead */
+ sprintf(buf, "%d.%d.%d.%d",
+ sin->sin_addr.S_un.S_un_b.s_b1,
+ sin->sin_addr.S_un.S_un_b.s_b2,
+ sin->sin_addr.S_un.S_un_b.s_b3,
+ sin->sin_addr.S_un.S_un_b.s_b4);
+ MultiByteToWideChar(CP_ACP, 0, buf, -1, wbuf, 16);
+ port = ntohs(sin->sin_port);
+
+ IDirectPlay8Address_Clear(pAddr);
+ IDirectPlay8Address_SetSP(pAddr, &CLSID_DP8SP_TCPIP);
+ IDirectPlay8Address_AddComponent(pAddr, DPNA_KEY_HOSTNAME,
+ wbuf, (strlenW(wbuf)+1)*sizeof(WCHAR),
+ DPNA_DATATYPE_STRING);
+ IDirectPlay8Address_AddComponent(pAddr, DPNA_KEY_PORT,
+ &port, sizeof(DWORD),
+ DPNA_DATATYPE_DWORD);
+
+ addrSPData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sockaddr_in));
+ memcpy(addrSPData, pvSPData, sizeof(struct sockaddr_in));
+
+ DPNET_Address_SetSPData(pAddr, addrSPData, SP_TCPIP_ReleaseAddressData,
+ SP_TCPIP_DuplicateAddressData);
+
+ return S_OK;
+}
+
+static void SP_TCPIP_CallRead(void *pvIface, tpReadNode *node, DWORD sent)
+{
+ PDIRECTPLAY8SERVICEPROVIDER iface = pvIface;
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+ IDirectPlay8Address *pAddr = NULL;
+ IDirectPlay8Address *pUseAddr;
+ dpPlayer *play;
+ BOOL keep = FALSE;
+
+ /* look for existing address object (from established connections) */
+ EnterCriticalSection(&This->dp8gdData->cs_player);
+ play = This->dp8gdData->remotePlayers;
+ while (play) {
+ IDirectPlay8AddressImpl *addr = (IDirectPlay8AddressImpl *)play->pAddress;
+ if (IsEqualGUID(&addr->guidSP, &CLSID_DP8SP_TCPIP) &&
+ !memcmp(addr->spData, node->Addr.pBufferData, node->Addr.dwBufferSize)) {
+ pAddr = play->pAddress;
+ IDirectPlay8Address_AddRef(pAddr);
+ break;
+ }
+ play = play->next;
+ }
+ LeaveCriticalSection(&This->dp8gdData->cs_player);
+
+ pUseAddr = pAddr;
+ if (!pUseAddr) {
+ /* not found, build new one */
+ DirectPlay8SP_TCPIP_BuildAddressFromSPData(iface, node->pAddr, node->Addr.pBufferData);
+ pUseAddr = node->pAddr;
+ }
+
+ if (TRACE_ON(dplay)) {
+ BUFFERDESC buf;
+ buf.dwBufferSize = sent;
+ buf.pBufferData = node->Data.pBufferData;
+ DPNET_ParsePacket(IPPROTO_UDP, (LPVOID)node->Addr.pBufferData, NULL, &buf, 1);
+ /* debug_hexdump(node->Data.pBufferData, node->Data.dwBufferSize); */
+ }
+
+ if (This->msgCallback) {
+ keep = This->msgCallback(This->dp8gdData, node->Data.pBufferData, sent, pUseAddr);
+ } else {
+ TRACE("packet ignored\n");
+ }
+
+ if (pAddr) IDirectPlay8Address_Release(pAddr);
+
+ node->Addr.dwBufferSize = sizeof(struct sockaddr_in);
+ if (keep) {
+ node->Data.pBufferData = HeapAlloc(GetProcessHeap(), 0, node->Data.dwBufferSize);
+ }
+}
+
+static BOOL SP_TCPIP_InitRead(void *pvIface, tpReadNode *node)
+{
+ PDIRECTPLAY8SERVICEPROVIDER iface = pvIface;
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+ DWORD sent = 0;
+ DWORD flags = 0;
+ int res;
+
+ TRACE("(%p, %p)\n", pvIface, node);
+
+ memset(&node->ovl, 0, sizeof(node->ovl));
+ node->ovl.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+ if (!node->ovl.hEvent) {
+ TRACE("could not create event\n");
+ return FALSE;
+ }
+ node->Addr.dwBufferSize = sizeof(struct sockaddr_in);
+ node->Addr.pBufferData = HeapAlloc(GetProcessHeap(), 0, node->Addr.dwBufferSize);
+ node->Data.dwBufferSize = This->dwMaxSize;
+ node->Data.pBufferData = HeapAlloc(GetProcessHeap(), 0, node->Data.dwBufferSize);
+ DPNET_CreateDirectPlay8Address(NULL, &IID_IDirectPlay8Address, (LPVOID*)&node->pAddr);
+ IDirectPlay8Address_SetSP(node->pAddr, &CLSID_DP8SP_TCPIP);
+ while (TRUE) {
+ /* request some data */
+ res = WSARecvFrom(This->socket, (LPWSABUF)&node->Data, 1, &sent, &flags,
+ (LPVOID)node->Addr.pBufferData, (LPINT)&node->Addr.dwBufferSize,
+ &node->ovl, NULL);
+ if (res < 0) {
+ int err = WSAGetLastError();
+ switch (err) {
+ case WSA_IO_PENDING:
+ TRACE("=> WSA_IO_PENDING\n");
+ return TRUE;
+ default:
+ TRACE("=> WSA error %d\n", err);
+ return FALSE;
+ }
+ }
+ /* got some already, process it */
+ SP_TCPIP_CallRead(pvIface, node, sent);
+ }
+}
+
+static BOOL SP_TCPIP_CompRead(void *pvIface, tpReadNode *node)
+{
+ PDIRECTPLAY8SERVICEPROVIDER iface = pvIface;
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+ DWORD sent = 0;
+ DWORD flags = 0;
+ int res;
+
+ TRACE("(%p, %p)\n", pvIface, node);
+
+ if (!WSAGetOverlappedResult(This->socket, &node->ovl, &sent, FALSE, &flags)) {
+ int err = WSAGetLastError();
+ TRACE("=> WSA error %d\n", err);
+ return FALSE;
+ }
+
+ while (TRUE) {
+ /* process data */
+ SP_TCPIP_CallRead(pvIface, node, sent);
+ /* request some more */
+ res = WSARecvFrom(This->socket, (LPWSABUF)&node->Data, 1, &sent, &flags,
+ (LPVOID)node->Addr.pBufferData, (LPINT)&node->Addr.dwBufferSize,
+ &node->ovl, NULL);
+ if (res < 0) {
+ int err = WSAGetLastError();
+ switch (err) {
+ case WSA_IO_PENDING:
+ TRACE("=> WSA_IO_PENDING\n");
+ return TRUE;
+ default:
+ TRACE("=> WSA error %d\n", err);
+ return FALSE;
+ }
+ }
+ }
+}
+
+HRESULT WINAPI
+DirectPlay8SP_TCPIP_ReturnBuffer(PDIRECTPLAY8SERVICEPROVIDER iface,
+ void *pk, DWORD dwFlags)
+{
+ /* ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); */
+ HeapFree(GetProcessHeap(), 0, pk);
+ return S_OK;
+}
+
+HRESULT WINAPI
+DirectPlay8SP_TCPIP_QueryInterface(PDIRECTPLAY8SERVICEPROVIDER iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDirectPlay8ServiceProvider, riid))
+ {
+ This->ref++;
+ *obj = This;
+ return S_OK;
+ }
+ else
+ {
+ FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj);
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG WINAPI
+DirectPlay8SP_TCPIP_AddRef(PDIRECTPLAY8SERVICEPROVIDER iface)
+{
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ return ++This->ref;
+}
+
+ULONG WINAPI
+DirectPlay8SP_TCPIP_Release(PDIRECTPLAY8SERVICEPROVIDER iface)
+{
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ if (--This->ref) return This->ref;
+
+ FIXME("destroy this and everything\n");
+ closesocket(This->socket);
+
+ if (This->threadPool)
+ IDirectPlay8ThreadPool_Release(This->threadPool);
+
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+}
+
+HRESULT WINAPI
+DirectPlay8SP_TCPIP_Initialize(PDIRECTPLAY8SERVICEPROVIDER iface,
+ DirectPlay8GlobalData *dp8gdData,
+ spMessageReceived msgCallback,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+ HRESULT hr;
+ struct sockaddr_in bind_sin;
+ int bind_err, port;
+
+ WORD version = MAKEWORD(2, 2);
+ WSADATA wsaData;
+
+ /* fixme: error checking, and much more */
+ TRACE("(%p)->(%p, %p, 0x%08x)\n", iface, dp8gdData, msgCallback, dwFlags);
+
+ This->dpnSPCaps.dwFlags = DPNSPCAPS_SUPPORTSALLADAPTERS;
+ This->dpnSPCaps.dwNumThreads = 4; /* windows: 3 */
+ This->dpnSPCaps.dwDefaultEnumCount = 5;
+ This->dpnSPCaps.dwDefaultEnumRetryInterval = 1500;
+ This->dpnSPCaps.dwDefaultEnumTimeout = 1500;
+ This->dpnSPCaps.dwMaxEnumPayloadSize = 0; /* windows: 983 */
+ This->dpnSPCaps.dwBuffersPerThread = 0; /* windows: 1 */
+ This->dpnSPCaps.dwSystemBufferSize = 0; /* windows: 8192 */
+
+
+ This->dp8gdData = dp8gdData;
+ This->msgCallback = msgCallback;
+
+ WSAStartup(version, &wsaData);
+ This->dwMaxSize = wsaData.iMaxUdpDg;
+ This->socket = socket(AF_INET, SOCK_DGRAM, 0);
+
+ TRACE("got socket: %p\n", This->socket);
+
+ port = 2302;
+ do
+ {
+ bind_sin.sin_port = htons(2302);
+ bind_sin.sin_family = AF_INET;
+ bind_sin.sin_addr.s_addr = INADDR_ANY;
+ bind_err = bind(This->socket, (struct sockaddr *)&bind_sin, sizeof(bind_sin));
+ port++;
+ } while (bind_err < 0 && port < 2400);
+ if (bind_err < 0)
+ FIXME("couldn't bind to a port, something could go wrong, maybe...\n");
+
+ hr = DPNET_GetThreadPool(&This->threadPool, This->dpnSPCaps.dwNumThreads);
+ if (FAILED(hr)) {
+ ERR("couldn't initialize thread pool: 0x%08x\n", hr);
+ return hr;
+ }
+ DPNET_InitAsyncRead(This->threadPool, SP_TCPIP_InitRead, SP_TCPIP_CompRead, This);
+
+ return S_OK;
+}
+
+static HRESULT SP_TCPIP_SetAddrDataFromHostname(PDIRECTPLAY8ADDRESS dp8Address,
+ WCHAR *pHostName, DWORD port)
+{
+ char *ahostname, *portpos;
+ int lenhostname;
+ struct sockaddr_in *addrSPData;
+
+ TRACE("(%p, %s)\n", dp8Address, debugstr_w(pHostName));
+
+ lenhostname = strlenW(pHostName)+1;
+ ahostname = (CHAR *)HeapAlloc(GetProcessHeap(), 0, lenhostname * sizeof(char));
+ WideCharToMultiByte(CP_ACP, -1, pHostName, -1, ahostname, lenhostname,
+ NULL, NULL);
+ if ((portpos = strchr(ahostname, ':')))
+ {
+ *portpos = '\0';
+ portpos += 1;
+ FIXME("support custom ports in hostname\n");
+ }
+ if (!port) port = 2302;
+
+ addrSPData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sockaddr_in));
+ addrSPData->sin_port = htons(port);
+ addrSPData->sin_family = AF_INET;
+
+ if ((addrSPData->sin_addr.s_addr = inet_addr(ahostname)) == INADDR_NONE)
+ {
+ struct hostent *host_ip;
+ if (!(host_ip = gethostbyname(ahostname)) || !host_ip->h_addr_list[0])
+ {
+ ERR("host name invalid. what do we do??\n");
+ return E_FAIL;
+ }
+
+ addrSPData->sin_addr.s_addr = inet_addr(host_ip->h_addr_list[0]);
+ }
+ HeapFree(GetProcessHeap(), 0, ahostname);
+ DPNET_Address_SetSPData(dp8Address, addrSPData, SP_TCPIP_ReleaseAddressData,
+ SP_TCPIP_DuplicateAddressData);
+ return S_OK;
+}
+
+/* no. this isn't quite right. We need a packet window like thing - and that thread should
+ * prompt for the address. Currently multiple threads can try to send things at once,
+ * this causes a problem in that multiple dialogs could come up at once.
+ * We get around this by grabbing a lock before testing the service provider.
+ * it is a HACK (David, 23/01/03) - but until we get some better packet management, it will
+ * have to do
+ */
+static HRESULT SP_TCPIP_GetSockAddress(PDIRECTPLAY8ADDRESS dp8Address,
+ struct sockaddr_in *sin)
+{
+ struct sockaddr_in *addrSPData;
+
+ TRACE("(%p, %p)\n", dp8Address, sin);
+
+ DPNET_Address_GetDialogLock(dp8Address);
+ DPNET_Address_GetSPData(dp8Address, (void **)&addrSPData);
+ if (!addrSPData)
+ { /* FIXME: all this should probably be somewhere else.. */
+ WCHAR *hostname = NULL;
+ DWORD size = 0;
+ DWORD type = 0;
+ DWORD port = 0;
+
+ if (IDirectPlay8Address_GetComponentByName(dp8Address, DPNA_KEY_HOSTNAME,
+ NULL, &size, &type) == DPNERR_BUFFERTOOSMALL
+ && size != 0)
+ {
+ DWORD portsize = sizeof(DWORD);
+ hostname = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * size);
+ IDirectPlay8Address_GetComponentByName(dp8Address, DPNA_KEY_HOSTNAME,
+ hostname, &size, &type);
+ /* type should be DPNA_DATATYPE_STRING*/
+
+ if (IDirectPlay8Address_GetComponentByName(dp8Address, DPNA_KEY_PORT,
+ &port, &portsize, &type) != S_OK)
+ port = 0;
+ }
+ else /* need to prompt for hostname */
+ {
+ DPNET_HostNameShowDialog(&hostname);
+
+ if (!hostname)
+ {
+ WARN("no host name specified\n");
+ DPNET_Address_ReleaseDialogLock(dp8Address);
+ return E_FAIL;
+ }
+ TRACE("hostname from dialog: %s\n", debugstr_w(hostname));
+ }
+
+ if (FAILED(SP_TCPIP_SetAddrDataFromHostname(dp8Address, hostname, port)))
+ {
+ if (size)
+ HeapFree(GetProcessHeap(), 0, hostname);
+ DPNET_Address_ReleaseDialogLock(dp8Address);
+ return E_FAIL;
+ }
+ DPNET_Address_GetSPData(dp8Address, (void **)&addrSPData);
+
+ if (size)
+ {
+ HeapFree(GetProcessHeap(), 0, hostname);
+ }
+ else
+ {
+ DPNET_HostNameFree(hostname);
+ }
+ }
+ memcpy(sin, addrSPData, sizeof(struct sockaddr_in));
+ DPNET_Address_ReleaseDialogLock(dp8Address);
+
+ return S_OK;
+}
+
+HRESULT WINAPI DirectPlay8SP_TCPIP_SendTo(PDIRECTPLAY8SERVICEPROVIDER iface,
+ IDirectPlay8Address *pAddrDest,
+ const DPN_BUFFER_DESC *prgBufferDesc,
+ const DWORD cBufferDesc,
+ DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+ struct sockaddr_in sin;
+ DWORD sent = 0;
+ HRESULT hr;
+ int res;
+
+ TRACE("(%p)->(%p, %p, %i, %08x)\n", iface, pAddrDest, prgBufferDesc, cBufferDesc, dwFlags);
+
+ hr = SP_TCPIP_GetSockAddress(pAddrDest, &sin);
+ if (hr != S_OK)
+ return hr;
+
+ if (TRACE_ON(dplay)) {
+ DWORD c;
+ DPNET_ParsePacket(IPPROTO_UDP, NULL, &sin, prgBufferDesc, cBufferDesc);
+ for (c=0; c<cBufferDesc; c++) {
+ debug_hexdump(prgBufferDesc[c].pBufferData, prgBufferDesc[c].dwBufferSize);
+ }
+ }
+
+ res = WSASendTo(This->socket, (LPWSABUF)prgBufferDesc, cBufferDesc,
+ &sent, 0, (LPVOID)&sin, sizeof(sin), NULL, NULL);
+ if (res < 0) {
+ int err = WSAGetLastError();
+ switch (err) {
+ case WSAEWOULDBLOCK:
+ TRACE("=> WSAEWOULDBLOCK\n");
+ return DPNERR_NOTREADY;
+ default:
+ TRACE("=> WSA error %d\n", err);
+ return DPNERR_GENERIC;
+ }
+ } else {
+ TRACE("sent %d bytes\n", sent);
+ return DPN_OK;
+ }
+}
+
+HRESULT WINAPI DirectPlay8SP_TCPIP_GetSPCaps(PDIRECTPLAY8SERVICEPROVIDER iface,
+ DPN_SP_CAPS *pdpnSPCaps,
+ DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface);
+
+ TRACE("(%p)->(%p, 0x%08x)\n", iface, pdpnSPCaps, dwFlags);
+ pdpnSPCaps->dwFlags = This->dpnSPCaps.dwFlags;
+ pdpnSPCaps->dwNumThreads = This->dpnSPCaps.dwNumThreads;
+ pdpnSPCaps->dwDefaultEnumCount = This->dpnSPCaps.dwDefaultEnumCount;
+ pdpnSPCaps->dwDefaultEnumRetryInterval = This->dpnSPCaps.dwDefaultEnumRetryInterval;
+ pdpnSPCaps->dwDefaultEnumTimeout = This->dpnSPCaps.dwDefaultEnumTimeout;
+ pdpnSPCaps->dwMaxEnumPayloadSize = This->dpnSPCaps.dwMaxEnumPayloadSize;
+ pdpnSPCaps->dwBuffersPerThread = This->dpnSPCaps.dwBuffersPerThread;
+ pdpnSPCaps->dwSystemBufferSize = This->dpnSPCaps.dwSystemBufferSize;
+
+ return S_OK;
+}
+
+HRESULT WINAPI DirectPlay8SP_TCPIP_SetSPAddressData(PDIRECTPLAY8SERVICEPROVIDER iface,
+ IDirectPlay8Address *pAddr)
+{
+/* ICOM_THIS(IDirectPlay8SP_TCPIPImpl, iface); */
+ WCHAR *hostname = NULL;
+ DWORD port = 0;
+ WCHAR port_str[20]; /* enough for a DWORD (port) */
+
+ WCHAR *fullHostname, *p;
+
+ DWORD bufferLen = 0;
+ DWORD data_type = 0;
+ HRESULT hr;
+
+ TRACE("(%p)->(%p)\n", iface, pAddr);
+
+ /* get hostname */
+ hr = IDirectPlay8Address_GetComponentByName(pAddr, DPNA_KEY_HOSTNAME,
+ NULL, &bufferLen, &data_type);
+ if (hr != DPNERR_BUFFERTOOSMALL) return hr;
+ if (data_type != DPNA_DATATYPE_STRING)
+ ERR("wrong data type for host name\n");
+ hostname = HeapAlloc(GetProcessHeap(), 0, bufferLen * sizeof(WCHAR));
+ IDirectPlay8Address_GetComponentByName(pAddr, DPNA_KEY_HOSTNAME,
+ hostname, &bufferLen, &data_type);
+
+ /* get port */
+ bufferLen = 0;
+ hr = IDirectPlay8Address_GetComponentByName(pAddr, DPNA_KEY_PORT,
+ &port, &bufferLen, &data_type);
+ if (SUCCEEDED(hr) && data_type == DPNA_DATATYPE_DWORD)
+ {
+ const WCHAR fmt[] = {'%', 'l', 'd', 0};
+ wsprintfW(port_str, fmt, port);
+ }
+ else if (hr != DPNERR_DOESNOTEXIST)
+ ERR("failed due to some other reason (bad)\n");
+
+ bufferLen = strlenW(hostname) + (port ? strlenW(port_str) : 0) + 2;
+
+ fullHostname = HeapAlloc(GetProcessHeap(), 0, bufferLen * sizeof(WCHAR));
+ strcpyW(fullHostname, hostname);
+ p = fullHostname + strlenW(hostname);
+ *p = (WCHAR) ':';
+ p++;
+ if (port) strcpyW(p, port_str);
+ TRACE("full host name from address: %s\n", debugstr_w(fullHostname));
+
+ SP_TCPIP_SetAddrDataFromHostname(pAddr, fullHostname, 0);
+ HeapFree(GetProcessHeap(), 0, hostname);
+ HeapFree(GetProcessHeap(), 0, fullHostname);
+ return S_OK;
+}
+
+static ICOM_VTABLE(IDirectPlay8ServiceProvider) directPlay8SP_TCPIPVT =
+{
+ DirectPlay8SP_TCPIP_QueryInterface,
+ DirectPlay8SP_TCPIP_AddRef,
+ DirectPlay8SP_TCPIP_Release,
+ DirectPlay8SP_TCPIP_Initialize,
+ DirectPlay8SP_TCPIP_SendTo,
+ (void*)0xdead1055,
+ DirectPlay8SP_TCPIP_GetSPCaps,
+ DirectPlay8SP_TCPIP_SetSPAddressData,
+ DirectPlay8SP_TCPIP_BuildAddressFromSPData,
+ DirectPlay8SP_TCPIP_ReturnBuffer
+};
+
+HRESULT DPNET_CreateDirectPlay8SP_TCPIP(IUnknown *pOuter, REFIID riid, LPVOID *ppobj)
+{
+ IDirectPlay8SP_TCPIPImpl *ipDP8SP_TCPIP;
+ HRESULT hr;
+ TRACE("()\n");
+ ipDP8SP_TCPIP = (IDirectPlay8SP_TCPIPImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(IDirectPlay8SP_TCPIPImpl));
+ if (ipDP8SP_TCPIP == NULL) return E_OUTOFMEMORY;
+ ICOM_VTBL(ipDP8SP_TCPIP) = &directPlay8SP_TCPIPVT;
+ DirectPlay8SP_TCPIP_AddRef((IDirectPlay8ServiceProvider *)ipDP8SP_TCPIP);
+ TRACE("Created new object: %p\n", ipDP8SP_TCPIP);
+ hr = DirectPlay8SP_TCPIP_QueryInterface((IDirectPlay8ServiceProvider *)ipDP8SP_TCPIP, riid, ppobj);
+ DirectPlay8SP_TCPIP_Release((IDirectPlay8ServiceProvider *)ipDP8SP_TCPIP);
+ if (SUCCEEDED(hr))
+ return S_OK;
+ else
+ return E_NOINTERFACE;
+}
diff --git a/dlls/dpnet/threadpool.c b/dlls/dpnet/threadpool.c
new file mode 100644
index 0000000..5656664
--- /dev/null
+++ b/dlls/dpnet/threadpool.c
@@ -0,0 +1,407 @@
+/* dpnet.dll
+ *
+ * Copyright (C) 2002-2007 TransGaming Inc.
+ * Written by: David Hammerton, Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wine/debug.h"
+#include "winerror.h"
+#include "winsock2.h"
+
+#include "dplay8.h"
+#include "dplobby8.h"
+#include "dplay8_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dplay);
+
+static ICOM_VTABLE(IDirectPlay8ThreadPool) directPlay8ThreadPoolVT;
+
+static IDirectPlay8ThreadPoolImpl *pThreadPool;
+
+static void DPNET_UpdateTimer(IDirectPlay8ThreadPoolImpl *This)
+{
+ EnterCriticalSection(&This->cs_timer);
+ CancelWaitableTimer(This->hTimer);
+ /* FIXME */
+ LeaveCriticalSection(&This->cs_timer);
+}
+
+static DWORD CALLBACK DPNET_ThreadProc(LPVOID arg)
+{
+ IDirectPlay8ThreadPoolImpl *This = pThreadPool;
+ tpThreadNode *node = arg;
+ HANDLE hTimer = This->hTimer;
+ HANDLE *objs = NULL;
+ DWORD count = 0, res;
+ BOOL recount = TRUE;
+
+ EnterCriticalSection(&node->cs);
+ node->dwID = GetCurrentThreadId();
+
+ for (;;) {
+ tpReadNode *rnode;
+
+ if (recount) {
+ /* init and count objects */
+ count = 2;
+ rnode = node->Read;
+ while (rnode) {
+ /* not-so-elegant way of calling init routine once... */
+ if (rnode->pfnInit) {
+ rnode->pfnInit(rnode->ctx, rnode);
+ rnode->pfnInit = NULL;
+ }
+ if (rnode->ovl.hEvent) count++;
+ rnode = rnode->next;
+ }
+ /* make array of objects */
+ objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE));
+ objs[0] = node->hJob;
+ objs[1] = hTimer;
+ count = 2;
+ rnode = node->Read;
+ while (rnode) {
+ if (rnode->ovl.hEvent) objs[count++] = rnode->ovl.hEvent;
+ rnode = rnode->next;
+ }
+ recount = FALSE;
+ }
+ LeaveCriticalSection(&node->cs);
+
+ /* start waiting */
+ res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
+
+ EnterCriticalSection(&node->cs);
+
+ if (res == WAIT_OBJECT_0) {
+ if (node->die_please) break;
+ recount = TRUE;
+ }
+ else if (res == WAIT_OBJECT_0+1) {
+ /* FIXME: check timeouts */
+ DPNET_UpdateTimer(This);
+ }
+ else if (res == WAIT_FAILED) {
+ ERR("wait failed\n");
+ }
+ else {
+ HANDLE hObj = objs[res - WAIT_OBJECT_0];
+ /* find which object got it */
+ rnode = node->Read;
+ while (rnode) {
+ if (rnode->ovl.hEvent == hObj) break;
+ rnode = rnode->next;
+ }
+ if (rnode) {
+ /* ah hah */
+ rnode->pfnRead(rnode->ctx, rnode);
+ }
+ else {
+ ERR("failed to locate object for handle %p\n", hObj);
+ }
+ }
+ }
+
+ /* cleanup */
+ while (node->Read) {
+ tpReadNode *rnode = node->Read;
+ node->Read = rnode->next;
+ if (rnode->ovl.hEvent) CloseHandle(rnode->ovl.hEvent);
+ if (rnode->Addr.pBufferData) HeapFree(GetProcessHeap(), 0, rnode->Addr.pBufferData);
+ if (rnode->Data.pBufferData) HeapFree(GetProcessHeap(), 0, rnode->Data.pBufferData);
+ if (rnode->pAddr) IDirectPlay8Address_Release(rnode->pAddr);
+ HeapFree(GetProcessHeap(), 0, rnode);
+ }
+ LeaveCriticalSection(&node->cs);
+ return 0;
+}
+
+static void DPNET_StartThreads(IDirectPlay8ThreadPool *iface)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ EnterCriticalSection(&This->cs_thread);
+ if (This == pThreadPool) {
+ while (This->dwCurThreads < This->dwNumThreads) {
+ tpThreadNode *node = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(tpThreadNode));
+ InitializeCriticalSection(&node->cs);
+ node->hJob = CreateEventA(NULL, FALSE, FALSE, NULL);
+ node->next = This->threads;
+ if (node->next) node->next->prev = node;
+ This->threads = node;
+ node->hThread = CreateThread(NULL, 0, DPNET_ThreadProc, node, 0, NULL);
+ This->dwCurThreads++;
+ }
+ }
+ LeaveCriticalSection(&This->cs_thread);
+ DPNET_UpdateTimer(This);
+}
+
+static void DPNET_StopThreads(IDirectPlay8ThreadPool *iface)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ EnterCriticalSection(&This->cs_thread);
+ if (This == pThreadPool) {
+ while (This->dwCurThreads) {
+ tpThreadNode *node = This->threads;
+ node->die_please = TRUE;
+ SetEvent(node->hJob);
+ WaitForSingleObject(node->hThread, INFINITE);
+ This->threads = node->next;
+ CloseHandle(node->hThread);
+ CloseHandle(node->hJob);
+ DeleteCriticalSection(&node->cs);
+ HeapFree(GetProcessHeap(), 0, node);
+ This->dwCurThreads--;
+ }
+ }
+ CancelWaitableTimer(This->hTimer);
+ LeaveCriticalSection(&This->cs_thread);
+}
+
+/* IDirectPlay8ThreadPool */
+HRESULT WINAPI
+DirectPlay8ThreadPool_QueryInterface(PDIRECTPLAY8THREADPOOL iface,
+ REFIID riid, LPVOID *obj)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDirectPlay8ThreadPool, riid))
+ {
+ This->ref++;
+ *obj = This;
+ return S_OK;
+ }
+#if 0
+ else if (IsEqualGUID(&IID_IDirectPlay8ThreadPool_Internal, riid))
+ {
+ This->ref++;
+ *obj = (LPVOID *)&This->lpVtbl2;
+ return S_OK;
+ }
+#endif
+ else
+ {
+ FIXME("(%p)->(%s, %p): no interface\n", iface, debugstr_guid(riid), obj);
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG WINAPI
+DirectPlay8ThreadPool_AddRef(PDIRECTPLAY8THREADPOOL iface)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ return ++This->ref;
+}
+
+ULONG WINAPI
+DirectPlay8ThreadPool_Release(PDIRECTPLAY8THREADPOOL iface)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ TRACE("(%p)->()\n", iface);
+ if (--This->ref) return This->ref;
+
+ IDirectPlay8ThreadPool_Close(iface, 0);
+
+ CloseHandle(This->hTimer);
+ DeleteCriticalSection(&This->cs_timer);
+ DeleteCriticalSection(&This->cs_thread);
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+}
+
+HRESULT WINAPI
+DirectPlay8ThreadPool_Initialize(PDIRECTPLAY8THREADPOOL iface,
+ PVOID const pvUserContext,
+ const PFNDPNMESSAGEHANDLER pfn,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ TRACE("(%p)->(%p, %p, %08x): stub\n", iface, pvUserContext, pfn, dwFlags);
+ if (pThreadPool) {
+ /* we should return DPNERR_NOTALLOWED if it was
+ * initialized by another dplay object? */
+ TRACE("=> already initialized\n");
+ return DPNERR_ALREADYINITIALIZED;
+ }
+ This->pfn = pfn;
+ This->pvUserContext = pvUserContext;
+ pThreadPool = This;
+ return S_OK;
+}
+
+HRESULT WINAPI
+DirectPlay8ThreadPool_Close(PDIRECTPLAY8THREADPOOL iface,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ FIXME("(%p)->(%08x): stub\n", iface, dwFlags);
+ if (pThreadPool != This) {
+ TRACE("=> not initialized\n");
+ return DPNERR_UNINITIALIZED;
+ }
+ DPNET_StopThreads(iface);
+ if (pThreadPool == This)
+ pThreadPool = NULL;
+ return S_OK;
+}
+
+HRESULT WINAPI
+DirectPlay8ThreadPool_GetThreadCount(PDIRECTPLAY8THREADPOOL iface,
+ const DWORD dwProcessorNum,
+ DWORD *const pdwNumThreads,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ FIXME("(%p)->(%08i, %p, %08x): semi-stub\n",
+ iface, dwProcessorNum, pdwNumThreads, dwFlags);
+ if (pThreadPool != This) {
+ TRACE("=> not initialized\n");
+ return DPNERR_UNINITIALIZED;
+ }
+ *pdwNumThreads = This->dwNumThreads;
+ return S_OK;
+}
+
+HRESULT WINAPI
+DirectPlay8ThreadPool_SetThreadCount(PDIRECTPLAY8THREADPOOL iface,
+ const DWORD dwProcessorNum,
+ const DWORD dwNumThreads,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ FIXME("(%p)->(%08i, %08i, %08x): semi-stub\n",
+ iface, dwProcessorNum, dwNumThreads, dwFlags);
+ if (pThreadPool != This) {
+ TRACE("=> not initialized\n");
+ return DPNERR_UNINITIALIZED;
+ }
+ This->dwNumThreads = dwNumThreads;
+ DPNET_StartThreads(iface);
+ return S_OK;
+}
+
+HRESULT WINAPI
+DirectPlay8ThreadPool_DoWork(PDIRECTPLAY8THREADPOOL iface,
+ const DWORD dwAllowedTimeSlice,
+ const DWORD dwFlags)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ FIXME("(%p)->(%08i, %08x): stub (if they are using this expect badness, app may not be thread safe when we need it to be)\n",
+ iface, dwAllowedTimeSlice, dwFlags);
+ if (pThreadPool != This) {
+ TRACE("=> not initialized\n");
+ return DPNERR_UNINITIALIZED;
+ }
+ return S_OK;
+}
+
+static ICOM_VTABLE(IDirectPlay8ThreadPool) directPlay8ThreadPoolVT =
+{
+ DirectPlay8ThreadPool_QueryInterface,
+ DirectPlay8ThreadPool_AddRef,
+ DirectPlay8ThreadPool_Release,
+ DirectPlay8ThreadPool_Initialize,
+ DirectPlay8ThreadPool_Close,
+ DirectPlay8ThreadPool_GetThreadCount,
+ DirectPlay8ThreadPool_SetThreadCount,
+ DirectPlay8ThreadPool_DoWork
+};
+
+HRESULT DPNET_CreateDirectPlay8ThreadPool(IUnknown *pOuter, REFIID riid, LPVOID *ppobj)
+{
+ IDirectPlay8ThreadPoolImpl *ipDP8TP;
+ HRESULT hr;
+ TRACE("()\n");
+ ipDP8TP = (IDirectPlay8ThreadPoolImpl *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof(IDirectPlay8ThreadPoolImpl));
+ if (ipDP8TP == NULL) return E_OUTOFMEMORY;
+ ICOM_VTBL(ipDP8TP) = &directPlay8ThreadPoolVT;
+#if 0
+ ipDP8TP->lpVtbl2 = &directPlay8ThreadPool_InternalVT;
+#endif
+ InitializeCriticalSection(&ipDP8TP->cs_thread);
+ InitializeCriticalSection(&ipDP8TP->cs_timer);
+ ipDP8TP->hTimer = CreateWaitableTimerA(NULL, FALSE, NULL);
+ IDirectPlay8ThreadPool_AddRef((PDIRECTPLAY8THREADPOOL)ipDP8TP);
+ TRACE("Created new object: %p\n", ipDP8TP);
+ hr = IDirectPlay8ThreadPool_QueryInterface((PDIRECTPLAY8THREADPOOL)ipDP8TP, riid, ppobj);
+ IDirectPlay8ThreadPool_Release((PDIRECTPLAY8THREADPOOL)ipDP8TP);
+ if (SUCCEEDED(hr))
+ return S_OK;
+ else
+ return E_NOINTERFACE;
+}
+
+HRESULT DPNET_GetThreadPool(IDirectPlay8ThreadPool **ppThreadPool, DWORD dwNumThreads)
+{
+ IDirectPlay8ThreadPool* pTP;
+ if (!pThreadPool) {
+ /* thread pool does not exist, create one */
+ HRESULT hr = DPNET_CreateDirectPlay8ThreadPool(NULL, &IID_IDirectPlay8ThreadPool, (LPVOID*)&pTP);
+ if (FAILED(hr))
+ return hr;
+ hr = IDirectPlay8ThreadPool_Initialize(pTP, NULL, NULL, 0);
+ if (SUCCEEDED(hr))
+ hr = IDirectPlay8ThreadPool_SetThreadCount(pTP, -1, dwNumThreads, 0);
+ if (SUCCEEDED(hr)) {
+ *ppThreadPool = pTP;
+ return S_OK;
+ }
+ IDirectPlay8ThreadPool_Release(pTP);
+ return hr;
+ } else {
+ /* thread pool already exist */
+ pTP = (LPVOID)pThreadPool;
+ *ppThreadPool = pTP;
+ IDirectPlay8ThreadPool_AddRef(pTP);
+ return S_OK;
+ }
+}
+
+/* This schedules async reads on *all* threads, so that multiple incoming packets
+ * can be processed in parallel. I think real dplay distributes its connections
+ * across the available threads to avoid overloading any of them, but I doubt we're
+ * going to have many enough connections for that to be an issue. */
+void DPNET_InitAsyncRead(IDirectPlay8ThreadPool *iface, tpInitFunc pfnInit, tpReadFunc pfnRead, void *data)
+{
+ ICOM_THIS(IDirectPlay8ThreadPoolImpl, iface);
+ EnterCriticalSection(&This->cs_thread);
+ if (This == pThreadPool) {
+ tpThreadNode *node = This->threads;
+ while (node) {
+ tpReadNode *rnode = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(tpReadNode));
+ rnode->ctx = data;
+ rnode->pfnInit = pfnInit;
+ rnode->pfnRead = pfnRead;
+ rnode->next = node->Read;
+ if (rnode->next) rnode->next->prev = rnode;
+ node->Read = rnode;
+ SetEvent(node->hJob);
+ node = node->next;
+ }
+ }
+ LeaveCriticalSection(&This->cs_thread);
+}
diff --git a/dlls/dpnet/version.rc b/dlls/dpnet/version.rc
index b6a8488..91ce570 100644
--- a/dlls/dpnet/version.rc
+++ b/dlls/dpnet/version.rc
@@ -1,26 +1,9 @@
-/*
- * Copyright 2004 Raphael Junqueira
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#define WINE_FILEDESCRIPTION_STR "Wine DirectPlay 8"
-#define WINE_FILENAME_STR "dpnet.dll"
#define WINE_FILEVERSION 5,3,0,900
-#define WINE_FILEVERSION_STR "5.3.0.900"
#define WINE_PRODUCTVERSION 5,3,0,900
-#define WINE_PRODUCTVERSION_STR "5.3"
+#define WINE_FILEDESCRIPTION_STR "Cedega DirectPlay"
+#define WINE_FILENAME_STR "dpnet.dll"
+#define WINE_PRODUCTVERSION_STR "5.3.0000000.900"
+#define WINE_PRODUCTNAME_STR "TransGaming Cedega"
+#define WINE_FILEVERSION_STR "5.3.0000000.900 built by: Cedega"
#include "wine/wine_common_ver.rc"
diff --git a/dlls/uuid/uuid.c b/dlls/uuid/uuid.c
index 4e9be90..6182f22 100644
--- a/dlls/uuid/uuid.c
+++ b/dlls/uuid/uuid.c
@@ -68,6 +68,9 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
#include "htiframe.h"
#include "urlhist.h"
#include "hlguids.h"
+#include "dplay8.h"
+#include "dpaddr.h"
+#include "dplobby8.h"
/* FIXME: cguids declares GUIDs but does not define their values */
@@ -79,6 +82,8 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
DEFINE_GUID(IID_IDirectPlaySP,0xc9f6360,0xcc61,0x11cf,0xac,0xec,0x00,0xaa,0x00,0x68,0x86,0xe3);
DEFINE_GUID(IID_ISFHelper,0x1fe68efb,0x1874,0x9812,0x56,0xdc,0x00,0x00,0x00,0x00,0x00,0x00);
DEFINE_GUID(IID_IDPLobbySP,0x5a4e5a20,0x2ced,0x11d0,0xa8,0x89,0x00,0xa0,0xc9,0x05,0x43,0x3c);
+DEFINE_GUID(IID_IDirectPlay8ThreadPool_Internal,0x12f40839,0xe7a3,0x399b,0xab,0x45,0x9e,0x43,0x3d,0x8b,0x31,0x96);
+DEFINE_GUID(IID_IDirectPlay8ServiceProvider,0x985e2c76,0x66bc,0x4d66,0xad,0x8e,0xed,0x38,0x1,0xf1,0xb4,0x59);
DEFINE_GUID(FMTID_SummaryInformation,0xF29F85E0,0x4FF9,0x1068,0xAB,0x91,0x08,0x00,0x2B,0x27,0xB3,0xD9);
DEFINE_GUID(FMTID_DocSummaryInformation,0xD5CDD502,0x2E9C,0x101B,0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE);
diff --git a/include/dpaddr.h b/include/dpaddr.h
index 8300729..240571b 100644
--- a/include/dpaddr.h
+++ b/include/dpaddr.h
@@ -21,13 +21,13 @@
#include <ole2.h>
#include <dplay8.h>
+#include <winsock2.h>
#ifdef __cplusplus
extern "C" {
#endif /* defined(__cplusplus) */
typedef REFIID DPNAREFIID;
-typedef struct sockaddr SOCKADDR;
/*****************************************************************************
* DirectPlay8Addr defines
@@ -56,6 +56,8 @@ typedef struct sockaddr SOCKADDR;
#define DPNA_KEY_FLOWCONTROL_A "flowcontrol"
#define DPNA_KEY_HOSTNAME_A "hostname"
#define DPNA_KEY_NAMEINFO_A "nameinfo"
+#define DPNA_KEY_NAT_RESOLVER_A "natresolver"
+#define DPNA_KEY_NAT_RESOLVER_USER_STRING_A "natresolveruserstring"
#define DPNA_KEY_PARITY_A "parity"
#define DPNA_KEY_PHONENUMBER_A "phonenumber"
#define DPNA_KEY_PORT_A "port"
@@ -94,6 +96,8 @@ typedef struct sockaddr SOCKADDR;
# define DPNA_KEY_FLOWCONTROL (const WCHAR []){ 'f','l','o','w','c','o','n','t','r','o','l',0 }
# define DPNA_KEY_HOSTNAME (const WCHAR []){ 'h','o','s','t','n','a','m','e',0 }
# define DPNA_KEY_NAMEINFO (const WCHAR []){ 'n','a','m','e','i','n','f','o',0 }
+# define DPNA_KEY_NAT_RESOLVER (const WCHAR []){'n', 'a', 't', 'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 0}
+# define DPNA_KEY_NAT_RESOLVER_USER_STRING (const WCHAR []){'n', 'a', 't', 'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 'u', 's', 'e', 'r', 's', 't', 'r', 'i', 'n', 'g', 0}
# define DPNA_KEY_PARITY (const WCHAR []){ 'p','a','r','i','t','y',0 }
# define DPNA_KEY_PHONENUMBER (const WCHAR []){ 'p','h','o','n','e','n','u','m','b','e','r',0 }
# define DPNA_KEY_PORT (const WCHAR []){ 'p','o','r','t',0 }
@@ -130,6 +134,8 @@ typedef struct sockaddr SOCKADDR;
# define DPNA_KEY_FLOWCONTROL L"flowcontrol"
# define DPNA_KEY_HOSTNAME L"hostname"
# define DPNA_KEY_NAMEINFO_A L"nameinfo"
+# define DPNA_KEY_NAT_RESOLVER L"natresolver"
+# define DPNA_KEY_NAT_RESOLVER_USER_STRING L"natresolveruserstring"
# define DPNA_KEY_PARITY L"parity"
# define DPNA_KEY_PHONENUMBER L"phonenumber"
# define DPNA_KEY_PORT L"port"
@@ -166,6 +172,8 @@ static const WCHAR DPNA_KEY_DEVICE[] = { 'd','e','v','i','c','e',0 };
static const WCHAR DPNA_KEY_FLOWCONTROL[] = { 'f','l','o','w','c','o','n','t','r','o','l',0 };
static const WCHAR DPNA_KEY_HOSTNAME[] = { 'h','o','s','t','n','a','m','e',0 };
static const WCHAR DPNA_KEY_NAMEINFO[] = { 'n','a','m','e','i','n','f','o',0 };
+static const WCHAR DPNA_KEY_NAT_RESOLVER[] = {'n', 'a', 't', 'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 0};
+static const WCHAR DPNA_KEY_NAT_RESOLVER_USER_STRING[] = {'n', 'a', 't', 'r', 'e', 's', 'o', 'l', 'v', 'e', 'r', 'u', 's', 'e', 'r', 's', 't', 'r', 'i', 'n', 'g', 0};
static const WCHAR DPNA_KEY_PARITY[] = { 'p','a','r','i','t','y',0 };
static const WCHAR DPNA_KEY_PHONENUMBER[] = { 'p','h','o','n','e','n','u','m','b','e','r',0 };
static const WCHAR DPNA_KEY_PORT[] = { 'p','o','r','t',0 };