You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1330 lines
36 KiB
1330 lines
36 KiB
/***************************************************************************
|
|
*
|
|
* Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: dpnhupnpdllmain.cpp
|
|
*
|
|
* Content: DPNHUPNP DLL entry points.
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ======== ======== =========
|
|
* 04/16/01 VanceO Split DPNATHLP into DPNHUPNP and DPNHPAST.
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "dpnhupnpi.h"
|
|
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// External globals
|
|
//=============================================================================
|
|
volatile LONG g_lOutstandingInterfaceCount = 0; // number of outstanding interfaces
|
|
|
|
DNCRITICAL_SECTION g_csGlobalsLock; // lock protecting all of the following globals
|
|
CBilink g_blNATHelpUPnPObjs; // bilink of all the NATHelpUPnP interface objects
|
|
DWORD g_dwHoldRand; // current random number sequence
|
|
|
|
DWORD g_dwUPnPMode; // whether using UPnP is enabled or not
|
|
#ifndef DPNBUILD_NOHNETFWAPI
|
|
DWORD g_dwHNetFWAPIMode; // whether using HomeNet firewall API is enabled or not
|
|
#endif // ! DPNBUILD_NOHNETFWAPI
|
|
DWORD g_dwSubnetMaskV4 = 0x00FFFFFF; // = 0xFFFFFF00 in Intel order = 255.255.255.0, a class C network
|
|
DWORD g_dwNoActiveNotifyPollInterval = 25000; // start by polling every 25 seconds
|
|
DWORD g_dwMinUpdateServerStatusInterval = 1000; // don't hit the network more often than every 1 second
|
|
BOOL g_fNoAsymmetricMappings = FALSE; // whether asymmetric mappings can be tried or not
|
|
BOOL g_fUseLeaseDurations = FALSE; // whether non-INFINITE lease durations for NAT mappings can be tried or not
|
|
INT g_iUnicastTTL = 1; // unicast TTL value, or 0 to use default set by OS; normally we use 1
|
|
INT g_iMulticastTTL = 1; // multicast TTL value, or 0 to use default set by OS; normally we use 1
|
|
DWORD g_dwUPnPAnnounceResponseWaitTime = 2500; // how long to allow for UPnP device announcement responses to arrive in ms
|
|
DWORD g_dwUPnPConnectTimeout = 15; // how long to wait to reconnect to the UPnP device in seconds (default is 15, much shorter than standard TCP/IP timeout)
|
|
DWORD g_dwUPnPResponseTimeout = 5000; // how long to wait for a response message from the UPnP device to arrive in ms once the TCP/IP connection is established
|
|
#ifndef DPNBUILD_NOHNETFWAPI
|
|
BOOL g_fMapUPnPDiscoverySocket = FALSE; // whether the UPnP discovery socket should be mapped or not
|
|
#endif // ! DPNBUILD_NOHNETFWAPI
|
|
BOOL g_fUseMulticastUPnPDiscovery = FALSE; // whether to multicast UPnP discovery messages instead of the default directed sends to the gateway
|
|
DWORD g_dwDefaultGatewayV4 = INADDR_BROADCAST; // fallback to broadcasting UPnP discovery messages when detecting the gateway fails
|
|
DWORD g_dwPollIntervalBackoff = 30000; // backoff an additional 0 to 30 seconds if no network changes occur
|
|
DWORD g_dwMaxPollInterval = 300000; // don't go more than 5 minutes without polling
|
|
BOOL g_fKeepPollingForRemoteGateway = FALSE; // whether to continue to search for new Internet gateway devices if none were found during startup
|
|
DWORD g_dwReusePortTime = 60000; // how long to keep using the same port for polling remote Internet gateway devices (default is 1 minute)
|
|
DWORD g_dwCacheLifeFound = 30000; // how long to cache QueryAddress results where the address was found
|
|
DWORD g_dwCacheLifeNotFound = 30000; // how long to cache QueryAddress results where the address was not found
|
|
#ifdef DBG
|
|
WCHAR g_wszUPnPTransactionLog[256] = L""; // log file location, or empty string if none
|
|
#endif // DBG
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// Defines
|
|
//=============================================================================
|
|
#define REGKEY_VALUE_GUID L"Guid"
|
|
#define REGKEY_VALUE_DIRECTPLAY8PRIORITY L"DirectPlay8Priority"
|
|
#define REGKEY_VALUE_DIRECTPLAY8INITFLAGS L"DirectPlay8InitFlags"
|
|
#define REGKEY_VALUE_UPNPMODE L"UPnPMode"
|
|
#ifndef DPNBUILD_NOHNETFWAPI
|
|
#define REGKEY_VALUE_HNETFWAPIMODE L"HNetFWAPIMode"
|
|
#endif // ! DPNBUILD_NOHNETFWAPI
|
|
#define REGKEY_VALUE_SUBNETMASKV4 L"SubnetMaskV4"
|
|
#define REGKEY_VALUE_NOACTIVENOTIFYPOLLINTERVAL L"NoActiveNotifyPollInterval"
|
|
#define REGKEY_VALUE_MINUPDATESERVERSTATUSINTERVAL L"MinUpdateServerStatusInterval"
|
|
#define REGKEY_VALUE_NOASYMMETRICMAPPINGS L"NoAsymmetricMappings"
|
|
#define REGKEY_VALUE_USELEASEDURATIONS L"UseLeaseDurations"
|
|
#define REGKEY_VALUE_UNICASTTTL L"UnicastTTL"
|
|
#define REGKEY_VALUE_MULTICASTTTL L"MulticastTTL"
|
|
#define REGKEY_VALUE_UPNPANNOUNCERESPONSEWAITTIME L"UPnPAnnounceResponseWaitTime"
|
|
#define REGKEY_VALUE_UPNPCONNECTTIMEOUT L"UPnPConnectTimeout"
|
|
#define REGKEY_VALUE_UPNPRESPONSETIMEOUT L"UPnPResponseTimeout"
|
|
#ifndef DPNBUILD_NOHNETFWAPI
|
|
#define REGKEY_VALUE_MAPUPNPDISCOVERYSOCKET L"MapUPnPDiscoverySocket"
|
|
#endif // ! DPNBUILD_NOHNETFWAPI
|
|
#define REGKEY_VALUE_USEMULTICASTUPNPDISCOVERY L"UseMulticastUPnPDiscovery"
|
|
#define REGKEY_VALUE_DEFAULTGATEWAYV4 L"GatewayV4"
|
|
#define REGKEY_VALUE_POLLINTERVALBACKOFF L"PollIntervalBackoff"
|
|
#define REGKEY_VALUE_MAXPOLLINTERVAL L"MaxPollInterval"
|
|
#define REGKEY_VALUE_KEEPPOLLINGFORREMOTEGATEWAY L"KeepPollingForRemoteGateway"
|
|
#define REGKEY_VALUE_REUSEPORTTIME L"ReusePortTime"
|
|
#define REGKEY_VALUE_CACHELIFEFOUND L"CacheLifeFound"
|
|
#define REGKEY_VALUE_CACHELIFENOTFOUND L"CacheLifeNotFound"
|
|
#ifdef DBG
|
|
#define REGKEY_VALUE_UPNPTRANSACTIONLOG L"UPnPTransactionLog"
|
|
#endif // DBG
|
|
|
|
|
|
#define DEFAULT_DIRECTPLAY8PRIORITY 1
|
|
#define DEFAULT_DIRECTPLAY8INITFLAGS 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// Local prototypes
|
|
//=============================================================================
|
|
BOOL InitializeProcessGlobals(void);
|
|
void CleanupProcessGlobals(void);
|
|
void InitializeGlobalRand(const DWORD dwSeed);
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DllMain"
|
|
//=============================================================================
|
|
// DllMain
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: DLL entry point.
|
|
//
|
|
// Arguments:
|
|
// HANDLE hDllInst - Handle to this DLL module instance.
|
|
// DWORD dwReason - Reason for calling this function.
|
|
// LPVOID lpvReserved - Reserved.
|
|
//
|
|
// Returns: TRUE if all goes well, FALSE otherwise.
|
|
//=============================================================================
|
|
BOOL WINAPI DllMain(HANDLE hDllInst,
|
|
DWORD dwReason,
|
|
LPVOID lpvReserved)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
|
|
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
DPFX(DPFPREP, 2, "====> ENTER: DLLMAIN(%p): Process Attach: %08lx, tid=%08lx",
|
|
DllMain, GetCurrentProcessId(), GetCurrentThreadId());
|
|
|
|
//
|
|
// Ignore thread attach/detach messages.
|
|
//
|
|
DisableThreadLibraryCalls((HMODULE) hDllInst);
|
|
|
|
//
|
|
// Attempt to initialize the OS abstraction layer.
|
|
//
|
|
if (DNOSIndirectionInit(0))
|
|
{
|
|
//
|
|
// Attempt to initialize process-global items.
|
|
//
|
|
if (! InitializeProcessGlobals())
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to initialize globals!");
|
|
DNOSIndirectionDeinit();
|
|
fResult = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to initialize OS indirection layer!");
|
|
fResult = FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
{
|
|
//
|
|
// Ignore.
|
|
//
|
|
break;
|
|
}
|
|
|
|
case DLL_THREAD_DETACH:
|
|
{
|
|
//
|
|
// Ignore.
|
|
//
|
|
break;
|
|
}
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
DPFX(DPFPREP, 2, "====> EXIT: DLLMAIN(%p): Process Detach %08lx, tid=%08lx",
|
|
DllMain, GetCurrentProcessId(), GetCurrentThreadId());
|
|
|
|
CleanupProcessGlobals();
|
|
|
|
DNOSIndirectionDeinit();
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
} // DllMain
|
|
|
|
|
|
|
|
|
|
#ifndef DPNBUILD_NOCOMREGISTER
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DllRegisterServer"
|
|
//=============================================================================
|
|
// DllRegisterServer
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Registers the DirectPlay NAT Helper UPnP COM object.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: HRESULT
|
|
// S_OK - Successfully unregistered DirectPlay NAT Helper UPnP.
|
|
// E_FAIL - Failed unregistering DirectPlay NAT Helper UPnP.
|
|
//=============================================================================
|
|
HRESULT WINAPI DllRegisterServer(void)
|
|
{
|
|
CRegistry RegObject;
|
|
|
|
|
|
#if ((defined(DBG)) && (defined(DIRECTX_REDIST)))
|
|
// For redist debug builds we append a 'd' to the name to allow both debug and retail to be installed on the system
|
|
#define MAIN_DLL_NAME L"dpnhupnpd.dll"
|
|
#else // ! DBG or ! DIRECTX_REDIST
|
|
#define MAIN_DLL_NAME L"dpnhupnp.dll"
|
|
#endif // ! DBG or ! DIRECTX_REDIST
|
|
|
|
//
|
|
// Register this COM object CLSID.
|
|
//
|
|
if (! CRegistry::Register(L"DirectPlayNATHelperUPnP.1",
|
|
L"DirectPlay NAT Helper UPnP Object",
|
|
MAIN_DLL_NAME,
|
|
&CLSID_DirectPlayNATHelpUPnP,
|
|
L"DirectPlayNATHelperUPnP"))
|
|
{
|
|
DPFX(DPFPREP, 0, "Could not register DirectPlay NAT Helper UPnP object!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// Write this object's GUID and DirectPlay8 availability to the registry.
|
|
//
|
|
|
|
if (! RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY, FALSE, TRUE))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't create DirectPlay NAT Helper UPnP key!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (! RegObject.WriteGUID(REGKEY_VALUE_GUID, CLSID_DirectPlayNATHelpUPnP))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't write GUID to registry!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (! RegObject.WriteDWORD(REGKEY_VALUE_DIRECTPLAY8PRIORITY, DEFAULT_DIRECTPLAY8PRIORITY))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't write DirectPlay8 priority to registry!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (! RegObject.WriteDWORD(REGKEY_VALUE_DIRECTPLAY8INITFLAGS, DEFAULT_DIRECTPLAY8INITFLAGS))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't write DirectPlay8 init flags to registry!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
RegObject.Close();
|
|
|
|
|
|
|
|
#ifndef DPNBUILD_NOHNETFWAPI
|
|
//
|
|
// Create the active firewall mappings storage subkey.
|
|
//
|
|
|
|
if (! RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY L"\\" REGKEY_ACTIVEFIREWALLMAPPINGS, FALSE, TRUE))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't create DirectPlay NAT Helper active firewall mappings key! Continuing.");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We don't need to grant access to everyone for the active firewall mappings
|
|
// because currently you need to be an administrator to add or remove mappings
|
|
// via the HomeNet API anyway.
|
|
//
|
|
#if 0
|
|
#ifdef WINNT
|
|
//
|
|
// If we're on NT, set the key security to allow everyone full access
|
|
// (except WRITE_DAC and WRITE_OWNER).
|
|
//
|
|
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
if (! RegObject.GrantAllAccessSecurityPermissions())
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed granting all-access permissions to active firewall mappings key! Continuing.");
|
|
}
|
|
}
|
|
#endif // WINNT
|
|
#endif
|
|
|
|
RegObject.Close();
|
|
}
|
|
#endif // ! DPNBUILD_NOHNETFWAPI
|
|
|
|
|
|
|
|
//
|
|
// Create the active NAT mappings storage subkey.
|
|
//
|
|
|
|
if (! RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY L"\\" REGKEY_ACTIVENATMAPPINGS, FALSE, TRUE))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't create DirectPlay NAT Helper active NAT mappings key! Continuing.");
|
|
}
|
|
else
|
|
{
|
|
#ifdef WINNT
|
|
//
|
|
// If we're on NT, set the key security to allow everyone full access
|
|
// (except WRITE_DAC and WRITE_OWNER).
|
|
// Since anyone can create or delete a NAT mapping already, there's no
|
|
// point in securing the registry entries that exist solely for crash
|
|
// cleanup.
|
|
//
|
|
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
if (! RegObject.GrantAllAccessSecurityPermissions())
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed granting all-access permissions to active NAT mappings key! Continuing.");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
RegObject.Close();
|
|
}
|
|
|
|
|
|
return S_OK;
|
|
} // DllRegisterServer
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DllUnregisterServer"
|
|
//=============================================================================
|
|
// DllUnregisterServer
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Unregisters the DirectPlay NAT Helper UPnP COM object.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: HRESULT
|
|
// S_OK - Successfully unregistered DirectPlay NAT Helper UPnP.
|
|
// E_FAIL - Failed unregistering DirectPlay NAT Helper UPnP.
|
|
//=============================================================================
|
|
STDAPI DllUnregisterServer(void)
|
|
{
|
|
CRegistry RegObject;
|
|
|
|
|
|
//
|
|
// Unregister the class.
|
|
//
|
|
if (! CRegistry::UnRegister(&CLSID_DirectPlayNATHelpUPnP))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to unregister DirectPlay NAT Helper UPnP object!");
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// Try removing all the subitems we registered.
|
|
//
|
|
|
|
if (! RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY, FALSE, FALSE))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't open DirectPlay NAT Helper key! Ignoring.");
|
|
}
|
|
else
|
|
{
|
|
#ifndef DPNBUILD_NOHNETFWAPI
|
|
if (! RegObject.DeleteSubKey(REGKEY_ACTIVEFIREWALLMAPPINGS))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't delete DirectPlay NAT Helper active firewall mappings key, there may still be subitems! Ignoring.");
|
|
}
|
|
#endif // ! DPNBUILD_NOHNETFWAPI
|
|
|
|
if (! RegObject.DeleteSubKey(REGKEY_ACTIVENATMAPPINGS))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't delete DirectPlay NAT Helper active NAT mappings key, there may still be subitems! Ignoring.");
|
|
}
|
|
|
|
if (! RegObject.DeleteValue(REGKEY_VALUE_GUID))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't delete GUID registry value! Ignoring.");
|
|
}
|
|
|
|
if (! RegObject.DeleteValue(REGKEY_VALUE_DIRECTPLAY8PRIORITY))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't delete DirectPlay8 priority registry value! Ignoring.");
|
|
}
|
|
|
|
if (! RegObject.DeleteValue(REGKEY_VALUE_DIRECTPLAY8INITFLAGS))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't delete DirectPlay8 init flags registry value! Ignoring.");
|
|
}
|
|
|
|
RegObject.Close();
|
|
}
|
|
|
|
return S_OK;
|
|
} // DllUnregisterServer
|
|
|
|
#endif // !DPNBUILD_NOCOMREGISTER
|
|
|
|
|
|
#ifndef WINCE
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DirectPlayNATHelpCreate"
|
|
//=============================================================================
|
|
// DirectPlayNATHelpCreate
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Creates an IDirectPlayNATHelp interface object.
|
|
//
|
|
// Arguments:
|
|
// GUID * pIID - Pointer to IDirectPlayNATHelp interface GUID.
|
|
// void ** ppvInterface - Place to store pointer to interface object
|
|
// created.
|
|
//
|
|
// Returns: HRESULT
|
|
// DPNH_OK - Creating the object was successful.
|
|
// DPNHERR_INVALIDPOINTER - The destination pointer is invalid.
|
|
// DPNHERR_OUTOFMEMORY - Not enough memory to create the object.
|
|
// E_NOINTERFACE - The requested interface was invalid.
|
|
//=============================================================================
|
|
HRESULT WINAPI DirectPlayNATHelpCreate(const GUID * pIID, void ** ppvInterface)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pIID, ppvInterface);
|
|
|
|
hr = DoCreateInstance(NULL, // no class factory object necessary
|
|
NULL, // ?
|
|
CLSID_DirectPlayNATHelpUPnP, // DirectPlayNATHelp class
|
|
(*pIID), // requested interface
|
|
ppvInterface); // place to store interface
|
|
|
|
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
|
|
|
|
return hr;
|
|
} // DirectPlayNATHelpCreate
|
|
|
|
#endif // !WINCE
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitializeProcessGlobals"
|
|
//=============================================================================
|
|
// InitializeProcessGlobals
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Initialize global items needed for the DLL to operate.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: TRUE if successful, FALSE if an error occurred.
|
|
//=============================================================================
|
|
BOOL InitializeProcessGlobals(void)
|
|
{
|
|
BOOL fReturn = TRUE;
|
|
|
|
|
|
if (! DNInitializeCriticalSection(&g_csGlobalsLock))
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
//
|
|
// Don't allow critical section reentry.
|
|
//
|
|
DebugSetCriticalSectionRecursionCount(&g_csGlobalsLock, 0);
|
|
|
|
|
|
g_blNATHelpUPnPObjs.Initialize();
|
|
|
|
|
|
//
|
|
// Seed the random number generator with the current time.
|
|
//
|
|
InitializeGlobalRand(GETTIMESTAMP());
|
|
|
|
|
|
return fReturn;
|
|
} // InitializeProcessGlobals
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CleanupProcessGlobals"
|
|
//=============================================================================
|
|
// CleanupProcessGlobals
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Releases global items used by DLL.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void CleanupProcessGlobals(void)
|
|
{
|
|
CBilink * pBilink;
|
|
CNATHelpUPnP * pNATHelpUPnP;
|
|
|
|
|
|
if (! g_blNATHelpUPnPObjs.IsEmpty())
|
|
{
|
|
//
|
|
// This assert is far more descriptive than hitting one of those in the
|
|
// cleanup code that complain about flags incorrectly being set.
|
|
//
|
|
DNASSERT(! "DPNHUPNP.DLL unloading without all objects having been released! The caller's DirectPlayNATHelpUPnP cleanup code needs to be fixed!");
|
|
|
|
|
|
//
|
|
// Force close all the objects still outstanding.
|
|
//
|
|
pBilink = g_blNATHelpUPnPObjs.GetNext();
|
|
while (pBilink != &g_blNATHelpUPnPObjs)
|
|
{
|
|
DNASSERT(! pBilink->IsEmpty());
|
|
pNATHelpUPnP = NATHELPUPNP_FROM_BILINK(pBilink);
|
|
pBilink = pBilink->GetNext();
|
|
|
|
|
|
DPFX(DPFPREP, 0, "Forcefully releasing object 0x%p!", pNATHelpUPnP);
|
|
|
|
pNATHelpUPnP->Close(0); // ignore error
|
|
|
|
|
|
//
|
|
// Forcefully remove it from the list and delete it instead of
|
|
// using pNATHelpUPnP->Release().
|
|
//
|
|
pNATHelpUPnP->m_blList.RemoveFromList();
|
|
pNATHelpUPnP->UninitializeObject();
|
|
delete pNATHelpUPnP;
|
|
}
|
|
}
|
|
|
|
DNDeleteCriticalSection(&g_csGlobalsLock);
|
|
} // CleanupProcessGlobals
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ReadRegistrySettings"
|
|
//=============================================================================
|
|
// ReadRegistrySettings
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Reads registry settings to override behavior of this DLL and to
|
|
// turn on some debugging features.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void ReadRegistrySettings(void)
|
|
{
|
|
CRegistry RegObject;
|
|
DWORD dwNewValue;
|
|
BOOL fNewValue;
|
|
#ifdef DBG
|
|
DWORD dwLength;
|
|
#endif // DBG
|
|
|
|
|
|
//
|
|
// Try opening the registry key.
|
|
//
|
|
if (RegObject.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY L"\\" REGKEY_COMPONENTSUBKEY) != FALSE)
|
|
{
|
|
//
|
|
// Lock out other interfaces from modifying the globals simultaneously.
|
|
//
|
|
DNEnterCriticalSection(&g_csGlobalsLock);
|
|
|
|
|
|
//
|
|
// If we successfully read a new mode, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_UPNPMODE, &dwNewValue))
|
|
{
|
|
g_dwUPnPMode = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using UPnP mode %u.", g_dwUPnPMode);
|
|
}
|
|
|
|
|
|
#ifndef DPNBUILD_NOHNETFWAPI
|
|
//
|
|
// If we successfully read a new mode, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_HNETFWAPIMODE, &dwNewValue))
|
|
{
|
|
g_dwUPnPMode = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using HNet FW API mode %u.", g_dwHNetFWAPIMode);
|
|
}
|
|
#endif // ! DPNBUILD_NOHNETFWAPI
|
|
|
|
|
|
//
|
|
// If we successfully read a new mask, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_SUBNETMASKV4, &dwNewValue))
|
|
{
|
|
g_dwSubnetMaskV4 = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using subnet mask 0x%08lx.", g_dwSubnetMaskV4);
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new interval, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_NOACTIVENOTIFYPOLLINTERVAL, &dwNewValue))
|
|
{
|
|
g_dwNoActiveNotifyPollInterval = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using no-active-notify recommended poll interval %u ms.", g_dwNoActiveNotifyPollInterval);
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new interval, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_MINUPDATESERVERSTATUSINTERVAL, &dwNewValue))
|
|
{
|
|
g_dwMinUpdateServerStatusInterval = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using minimum update-server-status interval %u ms.", g_dwMinUpdateServerStatusInterval);
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new boolean, save it.
|
|
//
|
|
if (RegObject.ReadBOOL(REGKEY_VALUE_NOASYMMETRICMAPPINGS, &fNewValue))
|
|
{
|
|
g_fNoAsymmetricMappings = fNewValue;
|
|
if (g_fNoAsymmetricMappings)
|
|
{
|
|
DPFX(DPFPREP, 1, "Never using asymmetric port mappings.");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is actually default behavior, but print out a statement
|
|
// anyway.
|
|
//
|
|
DPFX(DPFPREP, 1, "Asymmetric port mappings allowed by registry key.");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new boolean, save it.
|
|
//
|
|
if (RegObject.ReadBOOL(REGKEY_VALUE_USELEASEDURATIONS, &fNewValue))
|
|
{
|
|
g_fUseLeaseDurations = fNewValue;
|
|
if (g_fUseLeaseDurations)
|
|
{
|
|
DPFX(DPFPREP, 1, "Attempting to use non-INFINITE lease durations.");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is actually default behavior, but print out a statement
|
|
// anyway.
|
|
//
|
|
DPFX(DPFPREP, 1, "Non-INFINITE lease durations specifically prevented by registry key.");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new value, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_UNICASTTTL, &dwNewValue))
|
|
{
|
|
g_iUnicastTTL = dwNewValue;
|
|
if (g_iUnicastTTL != 0)
|
|
{
|
|
DPFX(DPFPREP, 1, "Using unicast TTL of %i.", g_iUnicastTTL);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Using OS default unicast TTL.");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new value, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_MULTICASTTTL, &dwNewValue))
|
|
{
|
|
g_iMulticastTTL = dwNewValue;
|
|
if (g_iMulticastTTL != 0)
|
|
{
|
|
DPFX(DPFPREP, 1, "Using multicast TTL of %i.", g_iMulticastTTL);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Using OS default multicast TTL.");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new timeout, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_UPNPANNOUNCERESPONSEWAITTIME, &dwNewValue))
|
|
{
|
|
g_dwUPnPAnnounceResponseWaitTime = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using UPnP announce response wait time of %u ms.", g_dwUPnPAnnounceResponseWaitTime);
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new timeout, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_UPNPCONNECTTIMEOUT, &dwNewValue))
|
|
{
|
|
g_dwUPnPConnectTimeout = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using UPnP connect timeout of %u seconds.", g_dwUPnPConnectTimeout);
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new timeout, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_UPNPRESPONSETIMEOUT, &dwNewValue))
|
|
{
|
|
g_dwUPnPResponseTimeout = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using UPnP response timeout of %u ms.", g_dwUPnPResponseTimeout);
|
|
}
|
|
|
|
|
|
#ifndef DPNBUILD_NOHNETFWAPI
|
|
//
|
|
// If we successfully read a new boolean, save it.
|
|
//
|
|
if (RegObject.ReadBOOL(REGKEY_VALUE_MAPUPNPDISCOVERYSOCKET, &fNewValue))
|
|
{
|
|
g_fMapUPnPDiscoverySocket = fNewValue;
|
|
if (g_fMapUPnPDiscoverySocket)
|
|
{
|
|
DPFX(DPFPREP, 1, "Mapping UPnP discovery socket on local firewall.");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is actually default behavior, but print out a statement
|
|
// anyway.
|
|
//
|
|
DPFX(DPFPREP, 1, "UPnP discovery socket mapping is disallowed by registry key.");
|
|
}
|
|
}
|
|
#endif // ! DPNBUILD_NOHNETFWAPI
|
|
|
|
|
|
//
|
|
// If we successfully read a new boolean, save it.
|
|
//
|
|
if (RegObject.ReadBOOL(REGKEY_VALUE_USEMULTICASTUPNPDISCOVERY, &fNewValue))
|
|
{
|
|
g_fUseMulticastUPnPDiscovery = fNewValue;
|
|
if (g_fUseMulticastUPnPDiscovery)
|
|
{
|
|
DPFX(DPFPREP, 1, "Using multicast UPnP discovery messages.");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is actually default behavior, but print out a statement
|
|
// anyway.
|
|
//
|
|
DPFX(DPFPREP, 1, "Multicasted UPnP discovery is disallowed by registry key.");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new default gateway, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_DEFAULTGATEWAYV4, &dwNewValue))
|
|
{
|
|
g_dwDefaultGatewayV4 = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using default gateway 0x%08lx.", g_dwDefaultGatewayV4);
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new value, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_POLLINTERVALBACKOFF, &dwNewValue))
|
|
{
|
|
if (dwNewValue != 0)
|
|
{
|
|
g_dwPollIntervalBackoff = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using poll interval backoff between 0 and %u ms.",
|
|
g_dwPollIntervalBackoff);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid poll interval backoff setting, using default between 0 and %u ms!",
|
|
g_dwPollIntervalBackoff);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new interval, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_MAXPOLLINTERVAL, &dwNewValue))
|
|
{
|
|
//
|
|
// Make sure the value is greater than the starting value.
|
|
//
|
|
if (dwNewValue >= g_dwNoActiveNotifyPollInterval)
|
|
{
|
|
g_dwMaxPollInterval = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Using max poll interval of %u ms.",
|
|
g_dwMaxPollInterval);
|
|
}
|
|
else
|
|
{
|
|
g_dwMaxPollInterval = g_dwNoActiveNotifyPollInterval;
|
|
DPFX(DPFPREP, 0, "Ignoring max poll interval of %u ms, the starting value is %u ms.",
|
|
g_dwMaxPollInterval);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Make sure the max poll interval default value is greater than
|
|
// the starting value because we may have read in a new
|
|
// g_dwNoActiveNotifyPollInterval that makes the default
|
|
// g_dwMaxPollInterval invalid.
|
|
//
|
|
if (g_dwMaxPollInterval < g_dwNoActiveNotifyPollInterval)
|
|
{
|
|
g_dwMaxPollInterval = g_dwNoActiveNotifyPollInterval;
|
|
DPFX(DPFPREP, 0, "Resetting max poll interval to %u ms so as to meet starting value.",
|
|
g_dwMaxPollInterval);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
|
|
// If we successfully read a new boolean, save it.
|
|
//
|
|
if (RegObject.ReadBOOL(REGKEY_VALUE_KEEPPOLLINGFORREMOTEGATEWAY, &fNewValue))
|
|
{
|
|
g_fKeepPollingForRemoteGateway = fNewValue;
|
|
if (g_fKeepPollingForRemoteGateway)
|
|
{
|
|
DPFX(DPFPREP, 1, "Will continue to poll for remote gateways.");
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is actually default behavior, but print out a statement
|
|
// anyway.
|
|
//
|
|
DPFX(DPFPREP, 1, "Continually polling for remote gateways is disallowed by registry key.");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new value, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_REUSEPORTTIME, &dwNewValue))
|
|
{
|
|
g_dwReusePortTime = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Reusing remote gateway discovery ports for %u ms.",
|
|
g_dwReusePortTime);
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new value, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_CACHELIFEFOUND, &dwNewValue))
|
|
{
|
|
g_dwCacheLifeFound = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Caching found addresses for %u ms.",
|
|
g_dwCacheLifeFound);
|
|
}
|
|
|
|
|
|
//
|
|
// If we successfully read a new value, save it.
|
|
//
|
|
if (RegObject.ReadDWORD(REGKEY_VALUE_CACHELIFENOTFOUND, &dwNewValue))
|
|
{
|
|
g_dwCacheLifeNotFound = dwNewValue;
|
|
DPFX(DPFPREP, 1, "Caching not-found addresses for %u ms.",
|
|
g_dwCacheLifeNotFound);
|
|
}
|
|
|
|
|
|
#ifdef DBG
|
|
//
|
|
|
|
// If we successfully read a log string, print that out.
|
|
//
|
|
dwLength = sizeof(g_wszUPnPTransactionLog) / sizeof(WCHAR);
|
|
|
|
if (RegObject.ReadString(REGKEY_VALUE_UPNPTRANSACTIONLOG,
|
|
g_wszUPnPTransactionLog,
|
|
&dwLength))
|
|
{
|
|
DPFX(DPFPREP, 1, "Using UPnP transaction log \"%ls\".", g_wszUPnPTransactionLog);
|
|
}
|
|
#endif // DBG
|
|
|
|
|
|
|
|
//
|
|
// Okay, we're done. Drop the lock.
|
|
//
|
|
DNLeaveCriticalSection(&g_csGlobalsLock);
|
|
|
|
|
|
//
|
|
// Done reading registry.
|
|
//
|
|
RegObject.Close();
|
|
}
|
|
} // ReadRegistrySettings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef WINCE
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "SetDefaultProxyBlanket"
|
|
//=============================================================================
|
|
// SetDefaultProxyBlanket
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Taken from the HomeNet config utils.
|
|
//
|
|
// This sets the standard COM security settings on the proxy
|
|
// for an object. Even if the CoSetProxyBlanket calls fail, pUnk
|
|
// remains in a usable state. Failure is expected in certain
|
|
// contexts, such as when, for example, we're being called within
|
|
// the desired process where we have direct pointers to the
|
|
// objects instead of going through a proxy.
|
|
//
|
|
// COM is assumed to have been initialized.
|
|
//
|
|
// Arguments:
|
|
// IUnknown * pUnk - The object on which to set the proxy blanket.
|
|
// char * szObjectName - (debug only) The name of the object.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
#ifdef DBG
|
|
void SetDefaultProxyBlanket(IUnknown * pUnk, const char * const szObjectName)
|
|
#else // ! DBG
|
|
void SetDefaultProxyBlanket(IUnknown * pUnk)
|
|
#endif // ! DBG
|
|
{
|
|
HRESULT hr;
|
|
//IUnknown * pUnkSet = NULL;
|
|
|
|
|
|
hr = CoSetProxyBlanket(pUnk,
|
|
RPC_C_AUTHN_WINNT, // use NT default security
|
|
RPC_C_AUTHN_NONE, // use NT default authentication
|
|
NULL, // must be NULL if default
|
|
RPC_C_AUTHN_LEVEL_CALL, // call level authentication
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL, // use process token
|
|
EOAC_NONE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
/*
|
|
hr = pUnk->QueryInterface(&pUnkSet);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
hr = CoSetProxyBlanket(pUnk,
|
|
RPC_C_AUTHN_WINNT, // use NT default security
|
|
RPC_C_AUTHN_NONE, // use NT default authentication
|
|
NULL, // must be NULL if default
|
|
RPC_C_AUTHN_LEVEL_CALL, // call level authentication
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL, // use process token
|
|
EOAC_NONE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// This is what we want.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Couldn't set security blanket (2) on %hs object 0x%p (err = 0x%lx)! Continuing.",
|
|
szObjectName, pUnk, hr);
|
|
}
|
|
|
|
pUnkSet->Release();
|
|
pUnkSet = NULL;
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Couldn't query for IUnknown interface on %hs object 0x%p (err = 0x%lx)! Continuing.",
|
|
szObjectName, pUnk, hr);
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Couldn't set security blanket (1) on %hs object 0x%p (err = 0x%lx)! Continuing.",
|
|
szObjectName, pUnk, hr);
|
|
}
|
|
} // SetDefaultProxyBlanket
|
|
|
|
#endif // ! WINCE
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitializeGlobalRand"
|
|
//=============================================================================
|
|
// InitializeGlobalRand
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Initializes the fallback global psuedo-random number
|
|
// generator, using the given seed value.
|
|
//
|
|
// Arguments:
|
|
// DWORD dwSeed - Seed to use.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void InitializeGlobalRand(const DWORD dwSeed)
|
|
{
|
|
//
|
|
// We don't need to hold a lock, since this should only be done once,
|
|
// during initialization time.
|
|
//
|
|
g_dwHoldRand = dwSeed;
|
|
} // InitializeGlobalRand
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "GetGlobalRand"
|
|
//=============================================================================
|
|
// GetGlobalRand
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Generates a pseudo-random DWORD.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: Pseudo-random number.
|
|
//=============================================================================
|
|
DWORD GetGlobalRand(void)
|
|
{
|
|
HCRYPTPROV hCryptProv;
|
|
DWORD dwResult;
|
|
WORD wResult1;
|
|
WORD wResult2;
|
|
#ifdef DBG
|
|
DWORD dwError;
|
|
#endif // DBG
|
|
|
|
|
|
if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
|
|
{
|
|
if (CryptGenRandom(hCryptProv, sizeof(dwResult), (BYTE*) (&dwResult)))
|
|
{
|
|
CryptReleaseContext(hCryptProv, 0);
|
|
return dwResult;
|
|
}
|
|
#ifdef DBG
|
|
else
|
|
{
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Crypto couldn't generate random number (err = %u)!",
|
|
dwError);
|
|
}
|
|
#endif // DBG
|
|
|
|
CryptReleaseContext(hCryptProv, 0);
|
|
}
|
|
#ifdef DBG
|
|
else
|
|
{
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Couldn't acquire crypto provider context (err = %u)!",
|
|
dwError);
|
|
}
|
|
#endif // DBG
|
|
|
|
|
|
//
|
|
// We couldn't use the crypto API to generate a random number, so make
|
|
// our own based off the C run time source.
|
|
//
|
|
|
|
DNEnterCriticalSection(&g_csGlobalsLock);
|
|
|
|
g_dwHoldRand = ((g_dwHoldRand * 214013L + 2531011L) >> 16) & 0x7fff;
|
|
wResult1 = (WORD) g_dwHoldRand;
|
|
g_dwHoldRand = ((g_dwHoldRand * 214013L + 2531011L) >> 16) & 0x7fff;
|
|
wResult2 = (WORD) g_dwHoldRand;
|
|
|
|
DNLeaveCriticalSection(&g_csGlobalsLock);
|
|
|
|
return MAKELONG(wResult1, wResult2);
|
|
} // GetGlobalRand
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DoCreateInstance"
|
|
//=============================================================================
|
|
// DoCreateInstance
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Creates an instance of an interface. Required by the general
|
|
// purpose class factory functions.
|
|
//
|
|
// Arguments:
|
|
// LPCLASSFACTORY This - Pointer to class factory.
|
|
// LPUNKNOWN pUnkOuter - Pointer to unknown interface.
|
|
// REFCLSID rclsid - Reference of GUID of desired interface.
|
|
// REFIID riid - Reference to another GUID?
|
|
// LPVOID * ppvObj - Pointer to pointer to interface.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
HRESULT DoCreateInstance(LPCLASSFACTORY This,
|
|
LPUNKNOWN pUnkOuter,
|
|
REFCLSID rclsid,
|
|
REFIID riid,
|
|
LPVOID * ppvObj)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fNotCreatedWithCOM;
|
|
CNATHelpUPnP * pNATHelpUPnP = NULL;
|
|
|
|
|
|
DNASSERT(ppvObj != NULL);
|
|
|
|
|
|
if (! IsEqualCLSID(rclsid, CLSID_DirectPlayNATHelpUPnP))
|
|
{
|
|
//
|
|
// This shouldn't happen if they called IClassFactory::CreateObject
|
|
// correctly.
|
|
//
|
|
DNASSERT(FALSE);
|
|
|
|
//
|
|
// Return an error.
|
|
//
|
|
hr = E_UNEXPECTED;
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// If the class factory pointer is NULL, then we were called by the
|
|
// DirectPlayNATHelpCreate function.
|
|
//
|
|
if (This == NULL)
|
|
{
|
|
fNotCreatedWithCOM = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fNotCreatedWithCOM = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Create the object instance.
|
|
//
|
|
pNATHelpUPnP = new CNATHelpUPnP(fNotCreatedWithCOM);
|
|
if (pNATHelpUPnP == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Initialize the base object (which might fail).
|
|
//
|
|
hr = pNATHelpUPnP->InitializeObject();
|
|
if (hr != S_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't initialize object!");
|
|
delete pNATHelpUPnP;
|
|
pNATHelpUPnP = NULL;
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Add it to the global list.
|
|
//
|
|
DNEnterCriticalSection(&g_csGlobalsLock);
|
|
|
|
pNATHelpUPnP->m_blList.InsertBefore(&g_blNATHelpUPnPObjs);
|
|
|
|
g_lOutstandingInterfaceCount++; // update count so DllCanUnloadNow works correctly
|
|
|
|
DNLeaveCriticalSection(&g_csGlobalsLock);
|
|
|
|
|
|
//
|
|
// Get the right interface for the caller and bump the refcount.
|
|
//
|
|
hr = pNATHelpUPnP->QueryInterface(riid, ppvObj);
|
|
if (hr != S_OK)
|
|
{
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
//
|
|
// Release the local reference to the object. If this function was
|
|
// successful, there's still a reference in ppvObj.
|
|
//
|
|
if (pNATHelpUPnP != NULL)
|
|
{
|
|
pNATHelpUPnP->Release();
|
|
pNATHelpUPnP = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
//
|
|
// Make sure we don't hand back a pointer.
|
|
//
|
|
(*ppvObj) = NULL;
|
|
|
|
goto Exit;
|
|
} // DoCreateInstance
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "IsClassImplemented"
|
|
//=============================================================================
|
|
// IsClassImplemented
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Determine if a class is implemented in this DLL. Required by
|
|
// the general purpose class factory functions.
|
|
//
|
|
// Arguments:
|
|
// REFCLSID rclsid - Reference to class GUID.
|
|
//
|
|
// Returns: BOOL
|
|
// TRUE - This DLL implements the class.
|
|
// FALSE - This DLL doesn't implement the class.
|
|
//=============================================================================
|
|
BOOL IsClassImplemented(REFCLSID rclsid)
|
|
{
|
|
return (IsEqualCLSID(rclsid, CLSID_DirectPlayNATHelpUPnP));
|
|
} // IsClassImplemented
|