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.
1810 lines
48 KiB
1810 lines
48 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: Utils.cpp
|
|
* Content: Serial service provider utility functions
|
|
*
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 11/25/98 jtk Created
|
|
***************************************************************************/
|
|
|
|
#include "dnmdmi.h"
|
|
|
|
|
|
//**********************************************************************
|
|
// Constant definitions
|
|
//**********************************************************************
|
|
|
|
#define DEFAULT_WIN9X_THREADS 1
|
|
|
|
static const WCHAR g_RegistryBase[] = L"SOFTWARE\\Microsoft\\DirectPlay8";
|
|
static const WCHAR g_RegistryKeyThreadCount[] = L"ThreadCount";
|
|
|
|
//
|
|
// default buffer size for getting TAPI device caps
|
|
//
|
|
static const DWORD g_dwDefaultTAPIDevCapsSize = 512;
|
|
|
|
//
|
|
// TAPI module name
|
|
//
|
|
static const TCHAR g_TAPIModuleName[] = TEXT("TAPI32.DLL");
|
|
|
|
//**********************************************************************
|
|
// Macro definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Structure definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Variable definitions
|
|
//**********************************************************************
|
|
|
|
//
|
|
// global variables that are unique for the process
|
|
//
|
|
#ifndef DPNBUILD_ONLYONETHREAD
|
|
static DNCRITICAL_SECTION g_InterfaceGlobalsLock;
|
|
#endif // !DPNBUILD_ONLYONETHREAD
|
|
|
|
static volatile LONG g_iThreadPoolRefCount = 0;
|
|
static CModemThreadPool *g_pThreadPool = NULL;
|
|
|
|
static volatile LONG g_iTAPIRefCount = 0;
|
|
static HMODULE g_hTAPIModule = NULL;
|
|
|
|
//**********************************************************************
|
|
// Function prototypes
|
|
//**********************************************************************
|
|
static void ReadSettingsFromRegistry( void );
|
|
static BYTE GetAddressEncryptionKey( void );
|
|
|
|
//**********************************************************************
|
|
// Function definitions
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ModemInitProcessGlobals - initialize the global items needed for the SP to operate
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// TRUE = success
|
|
// FALSE = failure
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ModemInitProcessGlobals"
|
|
|
|
BOOL ModemInitProcessGlobals( void )
|
|
{
|
|
BOOL fReturn;
|
|
BOOL fCriticalSectionInitialized;
|
|
DWORD iIndex;
|
|
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
fReturn = TRUE;
|
|
fCriticalSectionInitialized = FALSE;
|
|
|
|
|
|
#ifdef DBG
|
|
g_blDPNModemCritSecsHeld.Initialize();
|
|
#endif // DBG
|
|
|
|
|
|
ReadSettingsFromRegistry();
|
|
|
|
if ( DNInitializeCriticalSection( &g_InterfaceGlobalsLock ) == FALSE )
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
DebugSetCriticalSectionGroup( &g_InterfaceGlobalsLock, &g_blDPNModemCritSecsHeld ); // separate dpnmodem CSes from the rest of DPlay's CSes
|
|
|
|
fCriticalSectionInitialized = TRUE;
|
|
|
|
|
|
if ( ModemInitializePools() == FALSE )
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
|
|
// Load localized string from resources //////////////////////////////////////////////////////////////
|
|
for (iIndex = 0; iIndex < g_dwBaudRateCount; iIndex++)
|
|
{
|
|
if (!LoadString(g_hModemDLLInstance, IDS_BAUD_9600 + iIndex, g_BaudRate[iIndex].szLocalizedKey, 256))
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
for (iIndex = 0; iIndex < g_dwStopBitsCount; iIndex++)
|
|
{
|
|
if (!LoadString(g_hModemDLLInstance, IDS_STOPBITS_ONE + iIndex, g_StopBits[iIndex].szLocalizedKey, 256))
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
for (iIndex = 0; iIndex < g_dwParityCount; iIndex++)
|
|
{
|
|
if (!LoadString(g_hModemDLLInstance, IDS_PARITY_EVEN + iIndex, g_Parity[iIndex].szLocalizedKey, 256))
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
for (iIndex = 0; iIndex < g_dwFlowControlCount; iIndex++)
|
|
{
|
|
if (!LoadString(g_hModemDLLInstance, IDS_FLOW_NONE + iIndex, g_FlowControl[iIndex].szLocalizedKey, 256))
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
DNASSERT( g_pThreadPool == NULL );
|
|
|
|
Exit:
|
|
return fReturn;
|
|
|
|
Failure:
|
|
ModemDeinitializePools();
|
|
|
|
if ( fCriticalSectionInitialized != FALSE )
|
|
{
|
|
DNDeleteCriticalSection( &g_InterfaceGlobalsLock );
|
|
fCriticalSectionInitialized = FALSE;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ModemDeinitProcessGlobals - deinitialize the global items
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ModemDeinitProcessGlobals"
|
|
|
|
void ModemDeinitProcessGlobals( void )
|
|
{
|
|
DNASSERT( g_pThreadPool == NULL );
|
|
DNASSERT( g_iThreadPoolRefCount == 0 );
|
|
|
|
ModemDeinitializePools();
|
|
DNDeleteCriticalSection( &g_InterfaceGlobalsLock );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// InitializeInterfaceGlobals - perform global initialization for an interface.
|
|
// This entails starting the thread pool and RSIP (if applicable).
|
|
//
|
|
// Entry: Pointer to SPData
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitializeInterfaceGlobals"
|
|
|
|
HRESULT InitializeInterfaceGlobals( CModemSPData *const pSPData )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT( pSPData != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
DNEnterCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
if ( g_pThreadPool == NULL )
|
|
{
|
|
DNASSERT( g_iThreadPoolRefCount == 0 );
|
|
g_pThreadPool = (CModemThreadPool*)g_ModemThreadPoolPool.Get();
|
|
if ( g_pThreadPool == NULL )
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
else
|
|
{
|
|
if (!g_pThreadPool->Initialize())
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
g_ModemThreadPoolPool.Release(g_pThreadPool);
|
|
g_pThreadPool = NULL;
|
|
goto Failure;
|
|
}
|
|
|
|
g_iThreadPoolRefCount++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DNASSERT( g_iThreadPoolRefCount != 0 );
|
|
g_iThreadPoolRefCount++;
|
|
g_pThreadPool->AddRef();
|
|
}
|
|
|
|
Exit:
|
|
pSPData->SetThreadPool( g_pThreadPool );
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// DeinitializeInterfaceGlobals - deinitialize thread pool and Rsip
|
|
//
|
|
// Entry: Pointer to service provider
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DeinitializeInterfaceGlobals"
|
|
|
|
void DeinitializeInterfaceGlobals( CModemSPData *const pSPData )
|
|
{
|
|
CModemThreadPool *pThreadPool;
|
|
BOOL fCleanUp;
|
|
|
|
|
|
DNASSERT( pSPData != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pThreadPool = NULL;
|
|
fCleanUp = FALSE;
|
|
|
|
//
|
|
// Process as little as possible inside the lock. If any of the items
|
|
// need to be released, pointers to them will be set.
|
|
//
|
|
DNEnterCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
DNASSERT( g_pThreadPool != NULL );
|
|
DNASSERT( g_iThreadPoolRefCount != 0 );
|
|
DNASSERT( g_pThreadPool == pSPData->GetThreadPool() );
|
|
|
|
pThreadPool = pSPData->GetThreadPool();
|
|
|
|
//
|
|
// remove thread pool reference
|
|
//
|
|
g_iThreadPoolRefCount--;
|
|
if ( g_iThreadPoolRefCount == 0 )
|
|
{
|
|
g_pThreadPool = NULL;
|
|
fCleanUp = TRUE;
|
|
}
|
|
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
//
|
|
// now that we're outside of the lock, clean up the thread pool if this
|
|
// was the last reference to it
|
|
//
|
|
DNASSERT( pThreadPool != NULL );
|
|
if ( fCleanUp != FALSE )
|
|
{
|
|
pThreadPool->Deinitialize();
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// LoadTAPILibrary - load TAPI library
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "LoadTAPILibrary"
|
|
|
|
HRESULT LoadTAPILibrary( void )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
DNEnterCriticalSection( &g_InterfaceGlobalsLock );
|
|
if ( g_iTAPIRefCount != 0 )
|
|
{
|
|
DNASSERT( p_lineAnswer != NULL );
|
|
DNASSERT( p_lineClose != NULL );
|
|
DNASSERT( p_lineConfigDialog != NULL );
|
|
DNASSERT( p_lineDeallocateCall != NULL );
|
|
DNASSERT( p_lineDrop != NULL );
|
|
DNASSERT( p_lineGetDevCaps != NULL );
|
|
DNASSERT( p_lineGetID != NULL );
|
|
DNASSERT( p_lineGetMessage != NULL );
|
|
DNASSERT( p_lineInitializeEx != NULL );
|
|
DNASSERT( p_lineMakeCall != NULL );
|
|
DNASSERT( p_lineNegotiateAPIVersion != NULL );
|
|
DNASSERT( p_lineOpen != NULL );
|
|
DNASSERT( p_lineShutdown != NULL );
|
|
}
|
|
else
|
|
{
|
|
DNASSERT( g_hTAPIModule == NULL );
|
|
DNASSERT( p_lineAnswer == NULL );
|
|
DNASSERT( p_lineClose == NULL );
|
|
DNASSERT( p_lineConfigDialog == NULL );
|
|
DNASSERT( p_lineDeallocateCall == NULL );
|
|
DNASSERT( p_lineDrop == NULL );
|
|
DNASSERT( p_lineGetDevCaps == NULL );
|
|
DNASSERT( p_lineGetID == NULL );
|
|
DNASSERT( p_lineGetMessage == NULL );
|
|
DNASSERT( p_lineInitializeEx == NULL );
|
|
DNASSERT( p_lineMakeCall == NULL );
|
|
DNASSERT( p_lineNegotiateAPIVersion == NULL );
|
|
DNASSERT( p_lineOpen == NULL );
|
|
DNASSERT( p_lineShutdown == NULL );
|
|
|
|
g_hTAPIModule = LoadLibrary( g_TAPIModuleName );
|
|
if ( g_hTAPIModule == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to load TAPI!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineAnswer = reinterpret_cast<TAPI_lineAnswer*>( GetProcAddress( g_hTAPIModule, "lineAnswer" ) );
|
|
if ( p_lineAnswer == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineAnswer" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineClose = reinterpret_cast<TAPI_lineClose*>( GetProcAddress( g_hTAPIModule, "lineClose" ) );
|
|
if ( p_lineClose == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineClose" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineConfigDialog = reinterpret_cast<TAPI_lineConfigDialog*>( GetProcAddress( g_hTAPIModule, "lineConfigDialog" TAPI_APPEND_LETTER ) );
|
|
if ( p_lineConfigDialog == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineConfigDialog" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineDeallocateCall = reinterpret_cast<TAPI_lineDeallocateCall*>( GetProcAddress( g_hTAPIModule, "lineDeallocateCall" ) );
|
|
if ( p_lineDeallocateCall == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineDeallocateCall" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineDrop = reinterpret_cast<TAPI_lineDrop*>( GetProcAddress( g_hTAPIModule, "lineDrop" ) );
|
|
if ( p_lineDrop == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineDrop" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineGetDevCaps = reinterpret_cast<TAPI_lineGetDevCaps*>( GetProcAddress( g_hTAPIModule, "lineGetDevCaps" TAPI_APPEND_LETTER ) );
|
|
if ( p_lineGetDevCaps == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineGetDevCaps" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineGetID = reinterpret_cast<TAPI_lineGetID*>( GetProcAddress( g_hTAPIModule, "lineGetID" TAPI_APPEND_LETTER ) );
|
|
if ( p_lineGetID == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineGetID" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineGetMessage = reinterpret_cast<TAPI_lineGetMessage*>( GetProcAddress( g_hTAPIModule, "lineGetMessage" ) );
|
|
if ( p_lineGetMessage == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineGetMessage" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineInitializeEx = reinterpret_cast<TAPI_lineInitializeEx*>( GetProcAddress( g_hTAPIModule, "lineInitializeEx" TAPI_APPEND_LETTER ) );
|
|
if ( p_lineInitializeEx == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineInitializeEx" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineMakeCall = reinterpret_cast<TAPI_lineMakeCall*>( GetProcAddress( g_hTAPIModule, "lineMakeCall" TAPI_APPEND_LETTER ) );
|
|
if ( p_lineMakeCall == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineMakeCall" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineNegotiateAPIVersion = reinterpret_cast<TAPI_lineNegotiateAPIVersion*>( GetProcAddress( g_hTAPIModule, "lineNegotiateAPIVersion" ) );
|
|
if ( p_lineNegotiateAPIVersion == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineNegotiateAPIVersion" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineOpen = reinterpret_cast<TAPI_lineOpen*>( GetProcAddress( g_hTAPIModule, "lineOpen" TAPI_APPEND_LETTER ) );
|
|
if ( p_lineOpen == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineOpen" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
|
|
p_lineShutdown = reinterpret_cast<TAPI_lineShutdown*>( GetProcAddress( g_hTAPIModule, "lineShutdown" ) );
|
|
if ( p_lineShutdown == NULL )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to GetProcAddress for lineShutdown" );
|
|
DisplayErrorCode( 0, dwError );
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
DNASSERT( g_iTAPIRefCount != -1 );
|
|
g_iTAPIRefCount++;
|
|
|
|
Exit:
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
return hr;
|
|
|
|
Failure:
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
|
|
p_lineAnswer = NULL;
|
|
p_lineClose = NULL;
|
|
p_lineConfigDialog = NULL;
|
|
p_lineDeallocateCall = NULL;
|
|
p_lineDrop = NULL;
|
|
p_lineGetDevCaps = NULL;
|
|
p_lineGetID = NULL;
|
|
p_lineGetMessage = NULL;
|
|
p_lineInitializeEx = NULL;
|
|
p_lineMakeCall = NULL;
|
|
p_lineNegotiateAPIVersion = NULL;
|
|
p_lineOpen = NULL;
|
|
p_lineShutdown = NULL;
|
|
|
|
if ( g_hTAPIModule != NULL )
|
|
{
|
|
if ( FreeLibrary( g_hTAPIModule ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Problem unloading TAPI module on failed load!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
}
|
|
|
|
g_hTAPIModule = NULL;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// UnloadTAPILibrary - unload TAPI library
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "UnloadTAPILibrary"
|
|
|
|
void UnloadTAPILibrary( void )
|
|
{
|
|
DNEnterCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
DNASSERT( g_iTAPIRefCount != 0 );
|
|
g_iTAPIRefCount--;
|
|
if ( g_iTAPIRefCount == 0 )
|
|
{
|
|
DNASSERT( g_hTAPIModule != NULL );
|
|
DNASSERT( p_lineAnswer != NULL );
|
|
DNASSERT( p_lineClose != NULL );
|
|
DNASSERT( p_lineConfigDialog != NULL );
|
|
DNASSERT( p_lineDeallocateCall != NULL );
|
|
DNASSERT( p_lineDrop != NULL );
|
|
DNASSERT( p_lineGetDevCaps != NULL );
|
|
DNASSERT( p_lineGetID != NULL );
|
|
DNASSERT( p_lineGetMessage != NULL );
|
|
DNASSERT( p_lineInitializeEx != NULL );
|
|
DNASSERT( p_lineMakeCall != NULL );
|
|
DNASSERT( p_lineNegotiateAPIVersion != NULL );
|
|
DNASSERT( p_lineOpen != NULL );
|
|
DNASSERT( p_lineShutdown != NULL );
|
|
|
|
if ( FreeLibrary( g_hTAPIModule ) == FALSE )
|
|
{
|
|
DWORD dwError;
|
|
|
|
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Problem unloading TAPI module on failed load!" );
|
|
DisplayErrorCode( 0, dwError );
|
|
}
|
|
|
|
g_hTAPIModule = NULL;
|
|
p_lineAnswer = NULL;
|
|
p_lineClose = NULL;
|
|
p_lineConfigDialog = NULL;
|
|
p_lineDeallocateCall = NULL;
|
|
p_lineDrop = NULL;
|
|
p_lineGetDevCaps = NULL;
|
|
p_lineGetID = NULL;
|
|
p_lineGetMessage = NULL;
|
|
p_lineInitializeEx = NULL;
|
|
p_lineMakeCall = NULL;
|
|
p_lineNegotiateAPIVersion = NULL;
|
|
p_lineOpen = NULL;
|
|
p_lineShutdown = NULL;
|
|
}
|
|
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// IsSerialGUID - is a GUID a serial GUID?
|
|
//
|
|
// Entry: Pointer to GUID
|
|
//
|
|
// Exit: Boolean inficating whether the GUID is a serial GUID
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "IsSerialGUID"
|
|
|
|
BOOL IsSerialGUID( const GUID *const pGuid )
|
|
{
|
|
BOOL fReturn;
|
|
|
|
|
|
DNASSERT( pGuid != NULL );
|
|
|
|
//
|
|
// assume guid is serial
|
|
//
|
|
fReturn = TRUE;
|
|
|
|
//
|
|
// is this modem or serial?
|
|
//
|
|
if ( IsEqualCLSID( *pGuid, CLSID_DP8SP_MODEM ) == FALSE )
|
|
{
|
|
if ( IsEqualCLSID( *pGuid, CLSID_DP8SP_SERIAL ) == FALSE )
|
|
{
|
|
// not a known GUID
|
|
fReturn = FALSE;
|
|
}
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// StringToValue - convert a string to an enumerated value
|
|
//
|
|
// Entry: Pointer to string
|
|
// Length of string
|
|
// Pointer to destination enum
|
|
// Pointer to string/enum pairs
|
|
// Count of string/enum pairs
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// TRUE = value found
|
|
// FALSE = value not found
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "StringToValue"
|
|
|
|
BOOL StringToValue( const WCHAR *const pString,
|
|
const DWORD dwStringLength,
|
|
VALUE_ENUM_TYPE *const pEnum,
|
|
const STRING_BLOCK *const pStringBlock,
|
|
const DWORD dwPairCount )
|
|
{
|
|
BOOL fFound;
|
|
DWORD dwCount;
|
|
|
|
|
|
// initialize
|
|
fFound = FALSE;
|
|
dwCount = dwPairCount;
|
|
|
|
// loop through list
|
|
while ( ( dwCount > 0 ) && ( fFound == FALSE ) )
|
|
{
|
|
// make array index
|
|
dwCount--;
|
|
|
|
// are the strings the same length?
|
|
if ( pStringBlock[ dwCount ].dwWCHARKeyLength == dwStringLength )
|
|
{
|
|
// is this what we were looking for?
|
|
if ( memcmp( pString, pStringBlock[ dwCount ].pWCHARKey, dwStringLength ) == 0 )
|
|
{
|
|
// found it
|
|
fFound = TRUE;
|
|
*pEnum = pStringBlock[ dwCount ].dwEnumValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return fFound;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ValueToString - split extra info into components
|
|
//
|
|
// Entry: Pointer to pointer to string
|
|
// Length of string
|
|
// Enumerated value
|
|
// Pointer to string-enum pairs
|
|
// Count of string-enum pairs
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// TRUE = value was converted
|
|
// FALSE = value was not converted
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ValueToString"
|
|
|
|
BOOL ValueToString( const WCHAR **const ppString,
|
|
DWORD *const pdwStringLength,
|
|
const DWORD Enum,
|
|
const STRING_BLOCK *const pStringBlock,
|
|
const DWORD dwPairCount )
|
|
{
|
|
BOOL fFound;
|
|
DWORD dwCount;
|
|
|
|
|
|
// initialize
|
|
fFound = FALSE;
|
|
dwCount = dwPairCount;
|
|
|
|
// loop through strings
|
|
while ( ( dwCount > 0 ) && ( fFound == FALSE ))
|
|
{
|
|
// make array index
|
|
dwCount--;
|
|
|
|
// is this the enum?
|
|
if ( pStringBlock[ dwCount ].dwEnumValue == Enum )
|
|
{
|
|
// note that we found the value
|
|
*ppString = pStringBlock[ dwCount ].pWCHARKey;
|
|
*pdwStringLength = pStringBlock[ dwCount ].dwWCHARKeyLength;
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
|
|
return fFound;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ReadSettingsFromRegistry - read custom registry keys
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ReadSettingsFromRegistry"
|
|
|
|
static void ReadSettingsFromRegistry( void )
|
|
{
|
|
CRegistry RegObject;
|
|
|
|
|
|
if ( RegObject.Open( HKEY_LOCAL_MACHINE, g_RegistryBase ) != FALSE )
|
|
{
|
|
DWORD dwRegValue;
|
|
|
|
//
|
|
// read default threads
|
|
//
|
|
if ( RegObject.ReadDWORD( g_RegistryKeyThreadCount, &dwRegValue ) != FALSE )
|
|
{
|
|
g_iThreadCount = dwRegValue;
|
|
}
|
|
|
|
//
|
|
// if thread count is zero, use the 'default' for the system
|
|
//
|
|
if ( g_iThreadCount == 0 )
|
|
{
|
|
#ifdef WIN95
|
|
g_iThreadCount = DEFAULT_WIN9X_THREADS;
|
|
#else // WINNT
|
|
SYSTEM_INFO SystemInfo;
|
|
|
|
//
|
|
// as suggested by 'Multithreading Applications in Win32' book:
|
|
// dwNTThreadCount = ( ( processors * 2 ) + 2 )
|
|
//
|
|
memset( &SystemInfo, 0x00, sizeof( SystemInfo ) );
|
|
GetSystemInfo( &SystemInfo );
|
|
|
|
g_iThreadCount = ( ( 2 * SystemInfo.dwNumberOfProcessors ) + 2 );
|
|
#endif // WIN95
|
|
}
|
|
|
|
RegObject.Close();
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// GetAddressEncryptionKey - get a key used to encrypt device GUIDs
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Byte key
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "GetAddressEncryptionKey"
|
|
|
|
static BYTE GetAddressEncryptionKey( void )
|
|
{
|
|
BYTE bReturn;
|
|
UINT_PTR ProcessID;
|
|
|
|
bReturn = 0;
|
|
ProcessID = GetCurrentProcessId();
|
|
while ( ProcessID > 0 )
|
|
{
|
|
bReturn ^= ProcessID;
|
|
ProcessID >>= ( sizeof( bReturn ) * 8 );
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// DeviceIDToGuid - convert a device ID to an adapter GUID
|
|
//
|
|
// Entry: Reference of Guid to fill
|
|
// Device ID
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DeviceIDToGuid"
|
|
|
|
void DeviceIDToGuid( GUID *const pGuid, const UINT_PTR DeviceID, const GUID *const pEncryptionGuid )
|
|
{
|
|
DNASSERT( DeviceID < MAX_DATA_PORTS );
|
|
|
|
DNASSERT( sizeof( *pGuid ) == sizeof( *pEncryptionGuid ) );
|
|
memset( pGuid, 0x00, sizeof( *pGuid ) );
|
|
reinterpret_cast<BYTE*>( pGuid )[ 0 ] = static_cast<BYTE>( DeviceID );
|
|
|
|
ModemEncryptGuid( pGuid, pGuid, pEncryptionGuid );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// GuidToDeviceID - convert an adapter GUID to a device ID
|
|
//
|
|
// Entry: Reference of Guid
|
|
//
|
|
//
|
|
// Exit: Device ID
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "GuidToDeviceID"
|
|
|
|
DWORD GuidToDeviceID( const GUID *const pGuid, const GUID *const pEncryptionGuid )
|
|
{
|
|
GUID DecryptedGuid;
|
|
|
|
|
|
DNASSERT( pGuid != NULL );
|
|
DNASSERT( pEncryptionGuid != NULL );
|
|
|
|
ModemDecryptGuid( pGuid, &DecryptedGuid, pEncryptionGuid );
|
|
return reinterpret_cast<const BYTE*>( &DecryptedGuid )[ 0 ];
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ComDeviceIDToString - convert a COM device ID to a string
|
|
//
|
|
// Entry: Pointer to destination string (assumed to be large enough)
|
|
// Device ID
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ComDeviceIDToString"
|
|
|
|
void ComDeviceIDToString( TCHAR *const pString, const UINT_PTR uDeviceID )
|
|
{
|
|
UINT_PTR uTemp;
|
|
|
|
|
|
DNASSERT( uDeviceID < MAX_DATA_PORTS );
|
|
|
|
uTemp = uDeviceID;
|
|
memcpy( pString, TEXT("COM000"), COM_PORT_STRING_LENGTH * sizeof(TCHAR) );
|
|
pString[ 5 ] = ( static_cast<char>( uTemp % 10 ) ) + TEXT('0');
|
|
uTemp /= 10;
|
|
pString[ 4 ] = ( static_cast<char>( uTemp % 10 ) ) + TEXT('0');
|
|
uTemp /= 10;
|
|
pString[ 3 ] = ( static_cast<char>( uTemp % 10 ) ) + TEXT('0');
|
|
DNASSERT( uTemp < 10 );
|
|
|
|
if ( uDeviceID < 100 )
|
|
{
|
|
if ( uDeviceID < 10 )
|
|
{
|
|
DNASSERT( pString[ 3 ] == TEXT('0') );
|
|
DNASSERT( pString[ 4 ] == TEXT('0') );
|
|
pString[ 3 ] = pString[ 5 ];
|
|
pString[ 4 ] = TEXT('\0');
|
|
pString[ 5 ] = TEXT('\0');
|
|
}
|
|
else
|
|
{
|
|
DNASSERT( pString[ 3 ] == TEXT('0') );
|
|
pString[ 3 ] = pString[ 4 ];
|
|
pString[ 4 ] = pString[ 5 ];
|
|
pString[ 5 ] = TEXT('\0');
|
|
}
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// WideToANSI - convert a wide string to an ANSI string
|
|
//
|
|
// Entry: Pointer to source wide string
|
|
// Size of source string (in WCHAR units, -1 implies NULL-terminated)
|
|
// Pointer to ANSI string destination
|
|
// Pointer to size of ANSI destination
|
|
//
|
|
// Exit: Error code:
|
|
// DPNERR_GENERIC = operation failed
|
|
// DPN_OK = operation succeded
|
|
// DPNERR_BUFFERTOOSMALL = destination buffer too small
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "WideToAnsi"
|
|
|
|
HRESULT WideToAnsi( const WCHAR *const pWCHARString, const DWORD dwWCHARStringLength, char *const pString, DWORD *const pdwStringLength )
|
|
{
|
|
HRESULT hr;
|
|
int iReturn;
|
|
BOOL fDefault;
|
|
|
|
|
|
DNASSERT( pWCHARString != NULL );
|
|
DNASSERT( pdwStringLength != NULL );
|
|
DNASSERT( ( pString != NULL ) || ( &pdwStringLength == 0 ) );
|
|
|
|
hr = DPN_OK;
|
|
|
|
fDefault = FALSE;
|
|
iReturn = WideCharToMultiByte( CP_ACP, // code page (default ANSI)
|
|
0, // flags (none)
|
|
pWCHARString, // pointer to WCHAR string
|
|
dwWCHARStringLength, // size of WCHAR string
|
|
pString, // pointer to destination ANSI string
|
|
*pdwStringLength, // size of destination string
|
|
NULL, // pointer to default for unmappable characters (none)
|
|
&fDefault // pointer to flag indicating that default was used
|
|
);
|
|
if ( iReturn == 0 )
|
|
{
|
|
hr = DPNERR_GENERIC;
|
|
}
|
|
else
|
|
{
|
|
if ( *pdwStringLength == 0 )
|
|
{
|
|
hr = DPNERR_BUFFERTOOSMALL;
|
|
}
|
|
else
|
|
{
|
|
DNASSERT( hr == DPN_OK );
|
|
}
|
|
|
|
*pdwStringLength = iReturn;
|
|
}
|
|
|
|
//
|
|
// if you hit this ASSERT it's because you've probably got ASCII text as your
|
|
// input WCHAR string. Double-check your input!!
|
|
//
|
|
DNASSERT( fDefault == FALSE );
|
|
|
|
return hr;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ANSIToWide - convert an ANSI string to a wide string
|
|
//
|
|
// Entry: Pointer to source multi-byte (ANSI) string
|
|
// Size of source string (-1 imples NULL-terminated)
|
|
// Pointer to multi-byte string destination
|
|
// Pointer to size of multi-byte destination (in WCHAR units)
|
|
//
|
|
// Exit: Error code:
|
|
// ERR_FAIL - operation failed
|
|
// ERR_NONE - operation succeded
|
|
// ERR_BUFFER_TOO_SMALL - destination buffer too small
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "AnsiToWide"
|
|
|
|
HRESULT AnsiToWide( const char *const pString, const DWORD dwStringLength, WCHAR *const pWCHARString, DWORD *const pdwWCHARStringLength )
|
|
{
|
|
HRESULT hr;
|
|
int iReturn;
|
|
|
|
|
|
DNASSERT( pdwWCHARStringLength != 0 );
|
|
DNASSERT( ( pWCHARString != NULL ) || ( pdwWCHARStringLength == 0 ) );
|
|
DNASSERT( pString != NULL );
|
|
|
|
hr = DPN_OK;
|
|
iReturn = MultiByteToWideChar( CP_ACP, // code page (default ANSI)
|
|
0, // flags (none)
|
|
pString, // pointer to multi-byte string
|
|
dwStringLength, // size of string (assume null-terminated)
|
|
pWCHARString, // pointer to destination wide-char string
|
|
*pdwWCHARStringLength // size of destination in WCHARs
|
|
);
|
|
if ( iReturn == 0 )
|
|
{
|
|
hr = DPNERR_GENERIC;
|
|
}
|
|
else
|
|
{
|
|
if ( *pdwWCHARStringLength == 0 )
|
|
{
|
|
hr = DPNERR_BUFFERTOOSMALL;
|
|
}
|
|
else
|
|
{
|
|
DNASSERT( hr == DPN_OK );
|
|
}
|
|
|
|
*pdwWCHARStringLength = iReturn;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CreateSPData - create instance data for SP
|
|
//
|
|
// Entry: Pointer to pointer to SPData
|
|
// Pionter to class GUID
|
|
// Interface type
|
|
// Pointer to COM interface vtable
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CreateSPData"
|
|
|
|
HRESULT CreateSPData( CModemSPData **const ppSPData,
|
|
const SP_TYPE SPType,
|
|
IDP8ServiceProviderVtbl *const pVtbl )
|
|
{
|
|
HRESULT hr;
|
|
CModemSPData *pSPData;
|
|
|
|
|
|
DNASSERT( ppSPData != NULL );
|
|
DNASSERT( pVtbl != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
*ppSPData = NULL;
|
|
pSPData = NULL;
|
|
|
|
//
|
|
// create data
|
|
//
|
|
pSPData = new CModemSPData;
|
|
if ( pSPData == NULL )
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
DPFX(DPFPREP, 0, "Cannot create data for interface!" );
|
|
goto Failure;
|
|
}
|
|
pSPData->AddRef();
|
|
|
|
hr = pSPData->Initialize( SPType, pVtbl );
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to intialize SP data!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
Exit:
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem with CreateSPData!" );
|
|
DisplayDNError( 0, hr );
|
|
}
|
|
|
|
*ppSPData = pSPData;
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
if ( pSPData != NULL )
|
|
{
|
|
pSPData->DecRef();
|
|
pSPData = NULL;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// GenerateAvailableComPortList - generate a list of available com ports
|
|
//
|
|
// Entry: Pointer to list of Booleans to indicate availablility
|
|
// Maximum index of comport to enumerate
|
|
// Pointer to number of com ports found
|
|
//
|
|
// Exit: Error code
|
|
//
|
|
// Note: This function will fill in indicies 1 through uMaxDeviceIndex.
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "GenerateAvailableComPortList"
|
|
|
|
HRESULT GenerateAvailableComPortList( BOOL *const pfPortAvailable,
|
|
const UINT_PTR uMaxDeviceIndex,
|
|
DWORD *const pdwPortCount )
|
|
{
|
|
HRESULT hr;
|
|
UINT_PTR uIndex;
|
|
UINT_PTR uPortCount;
|
|
|
|
|
|
DNASSERT( pfPortAvailable != NULL );
|
|
DNASSERT( uMaxDeviceIndex != 0 );
|
|
DNASSERT( pdwPortCount != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
uPortCount = 0;
|
|
memset( pfPortAvailable, 0x00, ( sizeof( *pfPortAvailable ) * ( uMaxDeviceIndex + 1 ) ) );
|
|
*pdwPortCount = 0;
|
|
|
|
//
|
|
// attempt to open all COM ports in the specified range
|
|
//
|
|
uIndex = uMaxDeviceIndex;
|
|
while ( uIndex != 0 )
|
|
{
|
|
DNHANDLE hComFile;
|
|
TCHAR ComTemplate[ (COM_PORT_STRING_LENGTH+1) ];
|
|
DWORD dwError;
|
|
|
|
|
|
ComDeviceIDToString( ComTemplate, uIndex );
|
|
hComFile = DNCreateFile( ComTemplate, // comm port name
|
|
GENERIC_READ | GENERIC_WRITE, // read/write access
|
|
0, // don't share file with others
|
|
NULL, // default sercurity descriptor
|
|
OPEN_EXISTING, // comm port must exist to be opened
|
|
FILE_FLAG_OVERLAPPED, // use overlapped I/O
|
|
NULL // no handle for template file
|
|
);
|
|
if ( hComFile == DNINVALID_HANDLE_VALUE )
|
|
{
|
|
dwError = GetLastError();
|
|
if ( dwError != ERROR_ACCESS_DENIED )
|
|
{
|
|
//
|
|
// Don't bother displaying ERROR_FILE_NOT_FOUND, that's the usual
|
|
// error when you try to open a bogus COM port.
|
|
//
|
|
if ( dwError != ERROR_FILE_NOT_FOUND )
|
|
{
|
|
DPFX(DPFPREP, 9, "Couldn't open COM%u while enumerating com port adapters, err = %u.", uIndex, dwError );
|
|
DisplayErrorCode( 9, dwError );
|
|
}
|
|
|
|
goto SkipComPort;
|
|
}
|
|
|
|
DPFX(DPFPREP, 1, "Couldn't open COM%u, it is probably already in use.", uIndex );
|
|
|
|
//
|
|
// Consider the port as possibly available, continue.
|
|
//
|
|
}
|
|
|
|
//
|
|
// We found a valid COM port (it may be in use), note which COM port
|
|
// this is and then close our handle
|
|
//
|
|
pfPortAvailable[ uIndex ] = TRUE;
|
|
uPortCount++;
|
|
|
|
if ( hComFile != DNINVALID_HANDLE_VALUE )
|
|
{
|
|
if ( DNCloseHandle( hComFile ) == FALSE )
|
|
{
|
|
dwError = GetLastError();
|
|
DPFX(DPFPREP, 0, "Problem closing COM%u while enumerating com port adapters, err = %u!",
|
|
uIndex, dwError );
|
|
DisplayErrorCode( 0, dwError );
|
|
}
|
|
}
|
|
|
|
SkipComPort:
|
|
uIndex--;
|
|
}
|
|
|
|
DNASSERT( uPortCount <= UINT32_MAX );
|
|
DBG_CASSERT( sizeof( *pdwPortCount ) == sizeof( DWORD ) );
|
|
*pdwPortCount = static_cast<DWORD>( uPortCount );
|
|
|
|
return hr;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// GenerateAvailableModemList - generate list of available modems
|
|
//
|
|
// Entry: Pointer to TAPI data
|
|
// Pointer to modem count
|
|
// Pointer to data block
|
|
// Pointer to size of data block
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "GenerateAvailableModemList"
|
|
|
|
HRESULT GenerateAvailableModemList( const TAPI_INFO *const pTAPIInfo,
|
|
DWORD *const pdwModemCount,
|
|
MODEM_NAME_DATA *const pModemNameData,
|
|
DWORD *const pdwModemNameDataSize )
|
|
{
|
|
HRESULT hr;
|
|
LONG lLineReturn;
|
|
DWORD dwDeviceID;
|
|
DWORD dwDevCapsSize;
|
|
DWORD dwAPIVersion;
|
|
LINEDEVCAPS *pDevCaps;
|
|
LINEEXTENSIONID LineExtensionID;
|
|
DWORD dwRequiredBufferSize;
|
|
TCHAR *pOutputModemName;
|
|
|
|
|
|
DNASSERT( pdwModemCount != NULL );
|
|
DNASSERT( pdwModemNameDataSize != NULL );
|
|
DNASSERT( ( pModemNameData != NULL ) || ( *pdwModemNameDataSize == 0 ) );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
dwRequiredBufferSize = 0;
|
|
*pdwModemCount = 0;
|
|
pDevCaps = NULL;
|
|
|
|
if ( pModemNameData != NULL )
|
|
{
|
|
pOutputModemName = &(reinterpret_cast<TCHAR*>( pModemNameData )[ *pdwModemNameDataSize / sizeof(TCHAR) ]);
|
|
memset( pModemNameData, 0x00, *pdwModemNameDataSize );
|
|
}
|
|
else
|
|
{
|
|
pOutputModemName = NULL;
|
|
}
|
|
|
|
dwDevCapsSize = g_dwDefaultTAPIDevCapsSize;
|
|
pDevCaps = static_cast<LINEDEVCAPS*>( DNMalloc( dwDevCapsSize ) );
|
|
if ( pDevCaps == NULL )
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
dwDeviceID = pTAPIInfo->dwLinesAvailable;
|
|
if ( dwDeviceID > ( MAX_DATA_PORTS - 2 ) )
|
|
{
|
|
dwDeviceID = MAX_DATA_PORTS - 2;
|
|
DPFX(DPFPREP, 0, "Truncating to %d devices!", dwDeviceID );
|
|
}
|
|
|
|
Reloop:
|
|
while ( dwDeviceID != 0 )
|
|
{
|
|
dwDeviceID--;
|
|
|
|
memset( &LineExtensionID, 0x00, sizeof( LineExtensionID ) );
|
|
DNASSERT( p_lineNegotiateAPIVersion != NULL );
|
|
lLineReturn = p_lineNegotiateAPIVersion( pTAPIInfo->hApplicationInstance, // handle to TAPI instance
|
|
dwDeviceID, // device ID
|
|
0,
|
|
pTAPIInfo->dwVersion, // maximum TAPI version
|
|
&dwAPIVersion, // pointer to negotiated line version
|
|
&LineExtensionID // pointer to line extension infromation (none)
|
|
);
|
|
if ( lLineReturn != LINEERR_NONE )
|
|
{
|
|
//
|
|
// let this slide, just return no name string
|
|
//
|
|
switch ( lLineReturn )
|
|
{
|
|
//
|
|
// this TAPI device isn't up to our standards, ignore it
|
|
//
|
|
case LINEERR_INCOMPATIBLEAPIVERSION:
|
|
{
|
|
DPFX(DPFPREP, 0, "Rejecting TAPI device 0x%x because of API version!", dwDeviceID );
|
|
goto Reloop;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Device is not present. I don't know what causes
|
|
// this, but I saw it on one of my dev machines after
|
|
// I switched the modem from COM2 to COM1.
|
|
//
|
|
case LINEERR_NODEVICE:
|
|
{
|
|
DPFX(DPFPREP, 0, "Rejecting TAPI device 0x%x because it's not there!", dwDeviceID );
|
|
goto Reloop;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// This was seen in PnP stress.
|
|
//
|
|
case LINEERR_UNINITIALIZED:
|
|
{
|
|
DPFX(DPFPREP, 0, "Rejecting TAPI device 0x%x because it is not initialized!", dwDeviceID );
|
|
goto Reloop;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// other, stop and see what happened
|
|
//
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem getting line API version for device: %d", dwDeviceID );
|
|
DisplayTAPIError( 0, lLineReturn );
|
|
goto Reloop;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// ask for device caps
|
|
//
|
|
pDevCaps->dwTotalSize = dwDevCapsSize;
|
|
pDevCaps->dwNeededSize = dwDevCapsSize;
|
|
lLineReturn = LINEERR_STRUCTURETOOSMALL;
|
|
|
|
while ( lLineReturn == LINEERR_STRUCTURETOOSMALL )
|
|
{
|
|
DNASSERT( pDevCaps != NULL );
|
|
|
|
dwDevCapsSize = pDevCaps->dwNeededSize;
|
|
|
|
DNFree( pDevCaps );
|
|
pDevCaps = (LINEDEVCAPS*) DNMalloc( dwDevCapsSize );
|
|
if ( pDevCaps == NULL )
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
DPFX(DPFPREP, 0, "GetAvailableModemList: Failed to realloc memory on device %d!", dwDeviceID );
|
|
goto Failure;
|
|
}
|
|
|
|
pDevCaps->dwTotalSize = dwDevCapsSize;
|
|
pDevCaps->dwNeededSize = 0;
|
|
|
|
DNASSERT( p_lineGetDevCaps != NULL );
|
|
lLineReturn = p_lineGetDevCaps( pTAPIInfo->hApplicationInstance, // TAPI instance handle
|
|
dwDeviceID, // TAPI device ID
|
|
dwAPIVersion, // negotiated API version
|
|
0, // extended data version (none)
|
|
pDevCaps // pointer to device caps data
|
|
);
|
|
//
|
|
// TAPI lies about structures being too small!
|
|
// Double check the structure size ourselves.
|
|
//
|
|
if ( pDevCaps->dwNeededSize > dwDevCapsSize )
|
|
{
|
|
lLineReturn = LINEERR_STRUCTURETOOSMALL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If caps have been gotten, process them. Otherwise skip this device.
|
|
//
|
|
if ( lLineReturn == LINEERR_NONE )
|
|
{
|
|
//
|
|
// is this really a modem?
|
|
//
|
|
if ( ( pDevCaps->dwMediaModes & LINEMEDIAMODE_DATAMODEM ) != 0 )
|
|
{
|
|
//
|
|
// is this the modem name information accerptable?
|
|
//
|
|
if ( ( pDevCaps->dwLineNameSize != 0 ) &&
|
|
( pDevCaps->dwLineNameOffset != 0 ) )
|
|
{
|
|
//
|
|
// get the name of the device
|
|
//
|
|
DBG_CASSERT( sizeof( pDevCaps ) == sizeof( char* ) );
|
|
DWORD dwSize;
|
|
switch (pDevCaps->dwStringFormat)
|
|
{
|
|
case STRINGFORMAT_ASCII:
|
|
{
|
|
char* pLineName;
|
|
pLineName = &( reinterpret_cast<char*>( pDevCaps )[ pDevCaps->dwLineNameOffset ] );
|
|
//
|
|
// Note the required storage size and only copy it to the output
|
|
// if there's enough room. TAPI drivers are inconsistent. Some
|
|
// drivers return NULL terminated strings and others return strings
|
|
// with no NULL termination. Be paranoid and reserve space for an
|
|
// extra NULL for termination so we can always guarantee termination.
|
|
// This may waste a byte or two, but the user will never notice.
|
|
//
|
|
dwRequiredBufferSize += sizeof( *pModemNameData ) + (pDevCaps->dwLineNameSize * sizeof(TCHAR)) + sizeof( g_NullToken );
|
|
if ( dwRequiredBufferSize <= *pdwModemNameDataSize )
|
|
{
|
|
pModemNameData[ *pdwModemCount ].dwModemID = ModemIDFromTAPIID( dwDeviceID );
|
|
pModemNameData[ *pdwModemCount ].dwModemNameSize = pDevCaps->dwLineNameSize * sizeof(TCHAR);
|
|
|
|
pOutputModemName = &pOutputModemName[ - (static_cast<INT_PTR>( ((pDevCaps->dwLineNameSize * sizeof(TCHAR)) + sizeof( g_NullToken ) ) / sizeof(TCHAR))) ];
|
|
#ifndef UNICODE
|
|
memcpy( pOutputModemName, pLineName, pDevCaps->dwLineNameSize );
|
|
#else
|
|
dwSize = pDevCaps->dwLineNameSize * sizeof(TCHAR);
|
|
AnsiToWide(pLineName, pDevCaps->dwLineNameSize, pOutputModemName, &dwSize);
|
|
#endif // UNICODE
|
|
pModemNameData[ *pdwModemCount ].pModemName = pOutputModemName;
|
|
|
|
//
|
|
// Be paranoid about NULL termination. We've accounted for enough
|
|
// space to add a terminating NULL to the TAPI device name if one
|
|
// wasn't provided.
|
|
//
|
|
if ( pOutputModemName[ ((pDevCaps->dwLineNameSize * sizeof(TCHAR)) - sizeof( g_NullToken )) / sizeof(TCHAR) ] != g_NullToken )
|
|
{
|
|
pOutputModemName[ pDevCaps->dwLineNameSize ] = g_NullToken;
|
|
pModemNameData[ *pdwModemCount ].dwModemNameSize += sizeof( g_NullToken );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Note that the output buffer is too small, but still keep
|
|
// processing modem names.
|
|
//
|
|
hr = DPNERR_BUFFERTOOSMALL;
|
|
}
|
|
|
|
(*pdwModemCount)++;
|
|
DPFX(DPFPREP, 2, "Accepting modem device: 0x%x (ASCII)", dwDeviceID );
|
|
}
|
|
break;
|
|
|
|
case STRINGFORMAT_UNICODE:
|
|
{
|
|
WCHAR* pLineName;
|
|
pLineName = &( reinterpret_cast<WCHAR*>( pDevCaps )[ pDevCaps->dwLineNameOffset / sizeof(WCHAR)] );
|
|
//
|
|
// Note the required storage size and only copy it to the output
|
|
// if there's enough room. TAPI drivers are inconsistent. Some
|
|
// drivers return NULL terminated strings and others return strings
|
|
// with no NULL termination. Be paranoid and reserve space for an
|
|
// extra NULL for termination so we can always guarantee termination.
|
|
// This may waste a byte or two, but the user will never notice.
|
|
//
|
|
dwRequiredBufferSize += sizeof( *pModemNameData ) + ((pDevCaps->dwLineNameSize * sizeof(TCHAR)) / sizeof(WCHAR)) + sizeof( g_NullToken );
|
|
if ( dwRequiredBufferSize <= *pdwModemNameDataSize )
|
|
{
|
|
pModemNameData[ *pdwModemCount ].dwModemID = ModemIDFromTAPIID( dwDeviceID );
|
|
pModemNameData[ *pdwModemCount ].dwModemNameSize = pDevCaps->dwLineNameSize * (sizeof(TCHAR) / sizeof(WCHAR));
|
|
|
|
pOutputModemName = &pOutputModemName[ - (static_cast<INT_PTR>( (((pDevCaps->dwLineNameSize * sizeof(TCHAR)) / sizeof(WCHAR)) + sizeof( g_NullToken ) ) / sizeof(TCHAR))) ];
|
|
#ifdef UNICODE
|
|
memcpy( pOutputModemName, pLineName, pDevCaps->dwLineNameSize );
|
|
#else
|
|
dwSize = pDevCaps->dwLineNameSize / sizeof(TCHAR);
|
|
WideToAnsi(pLineName, pDevCaps->dwLineNameSize / sizeof(WCHAR), pOutputModemName, &dwSize);
|
|
#endif // UNICODE
|
|
pModemNameData[ *pdwModemCount ].pModemName = pOutputModemName;
|
|
|
|
//
|
|
// Be paranoid about NULL termination. We've accounted for enough
|
|
// space to add a terminating NULL to the TAPI device name if one
|
|
// wasn't provided.
|
|
//
|
|
if ( pOutputModemName[ (((pDevCaps->dwLineNameSize*sizeof(TCHAR))/sizeof(WCHAR)) - sizeof( g_NullToken )) / sizeof(TCHAR) ] != g_NullToken )
|
|
{
|
|
pOutputModemName[ pDevCaps->dwLineNameSize / sizeof(WCHAR) ] = g_NullToken;
|
|
pModemNameData[ *pdwModemCount ].dwModemNameSize += sizeof( g_NullToken );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Note that the output buffer is too small, but still keep
|
|
// processing modem names.
|
|
//
|
|
hr = DPNERR_BUFFERTOOSMALL;
|
|
}
|
|
|
|
(*pdwModemCount)++;
|
|
DPFX(DPFPREP, 2, "Accepting modem device: 0x%x (Unicode)", dwDeviceID );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
hr = DPNERR_GENERIC;
|
|
DPFX(DPFPREP, 0, "Problem with modem name for device: 0x%x!", dwDeviceID );
|
|
DNASSERT( FALSE );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = DPNERR_GENERIC;
|
|
DPFX(DPFPREP, 0, "Problem with modem name for device: 0x%x!", dwDeviceID );
|
|
DNASSERT( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Ignoring non-datamodem device: 0x%x", dwDeviceID );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to get device caps. Ignoring device: 0x%x", dwDeviceID );
|
|
}
|
|
}
|
|
|
|
*pdwModemNameDataSize = dwRequiredBufferSize;
|
|
|
|
Exit:
|
|
if ( pDevCaps != NULL )
|
|
{
|
|
DNFree( pDevCaps );
|
|
pDevCaps = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// PhoneNumberToWCHAR - convert a phone number to WCHAR
|
|
//
|
|
// Entry: Pointer to phone number
|
|
// Pointer to WCHAR destination
|
|
// Pointer to size of WCHAR destintion
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#ifndef UNICODE
|
|
HRESULT PhoneNumberToWCHAR( const char *const pPhoneNumber,
|
|
WCHAR *const pWCHARPhoneNumber,
|
|
DWORD *const pdwWCHARPhoneNumberSize )
|
|
{
|
|
HRESULT hr;
|
|
char *pOutput;
|
|
DWORD dwInputIndex;
|
|
DWORD dwOutputIndex;
|
|
|
|
|
|
DNASSERT( pPhoneNumber != NULL );
|
|
DNASSERT( pWCHARPhoneNumber != NULL );
|
|
DNASSERT( pdwWCHARPhoneNumberSize != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
pOutput = reinterpret_cast<char*>( pWCHARPhoneNumber );
|
|
dwInputIndex = 0;
|
|
dwOutputIndex = 0;
|
|
memset( pWCHARPhoneNumber, 0, ( (*pdwWCHARPhoneNumberSize) * sizeof( *pWCHARPhoneNumber ) ) );
|
|
|
|
while ( pPhoneNumber[ dwInputIndex ] != '\0' )
|
|
{
|
|
if ( dwInputIndex < ( *pdwWCHARPhoneNumberSize ) )
|
|
{
|
|
pOutput[ dwOutputIndex ] = pPhoneNumber[ dwInputIndex ];
|
|
}
|
|
|
|
dwOutputIndex += sizeof( *pWCHARPhoneNumber );
|
|
dwInputIndex += sizeof( *pPhoneNumber );
|
|
}
|
|
|
|
*pdwWCHARPhoneNumberSize = dwInputIndex + 1;
|
|
|
|
return hr;
|
|
}
|
|
#endif // !UNICODE
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// PhoneNumberFromWCHAR - convert a phone number from WCHAR
|
|
//
|
|
// Entry: Pointer to WCHAR phone number
|
|
// Pointer to phone number destination
|
|
// Pointer to phone destination size
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#ifndef UNICODE
|
|
HRESULT PhoneNumberFromWCHAR( const WCHAR *const pWCHARPhoneNumber,
|
|
char *const pPhoneNumber,
|
|
DWORD *const pdwPhoneNumberSize )
|
|
{
|
|
HRESULT hr;
|
|
const char *pInput;
|
|
DWORD dwInputIndex;
|
|
DWORD dwOutputIndex;
|
|
|
|
|
|
DNASSERT( pWCHARPhoneNumber != NULL );
|
|
DNASSERT( pPhoneNumber != NULL );
|
|
DNASSERT( pdwPhoneNumberSize != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
pInput = reinterpret_cast<const char*>( pWCHARPhoneNumber );
|
|
dwInputIndex = 0;
|
|
dwOutputIndex = 0;
|
|
memset( pPhoneNumber, 0x00, *pdwPhoneNumberSize );
|
|
|
|
while ( pInput[ dwInputIndex ] != '\0' )
|
|
{
|
|
if ( dwOutputIndex < *pdwPhoneNumberSize )
|
|
{
|
|
pPhoneNumber[ dwOutputIndex ] = pInput[ dwInputIndex ];
|
|
}
|
|
|
|
dwInputIndex += sizeof( *pWCHARPhoneNumber );
|
|
dwOutputIndex += sizeof( *pPhoneNumber );
|
|
}
|
|
|
|
*pdwPhoneNumberSize = dwOutputIndex + 1;
|
|
|
|
return hr;
|
|
}
|
|
#endif // !UNICODE
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ModemEncryptGuid - encrypt a guid
|
|
//
|
|
// Entry: Pointer to source guid
|
|
// Pointer to destination guid
|
|
// Pointer to encryption key
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ModemEncryptGuid"
|
|
|
|
void ModemEncryptGuid( const GUID *const pSourceGuid,
|
|
GUID *const pDestinationGuid,
|
|
const GUID *const pEncryptionKey )
|
|
{
|
|
const char *pSourceBytes;
|
|
char *pDestinationBytes;
|
|
const char *pEncryptionBytes;
|
|
DWORD_PTR dwIndex;
|
|
|
|
|
|
DNASSERT( pSourceGuid != NULL );
|
|
DNASSERT( pDestinationGuid != NULL );
|
|
DNASSERT( pEncryptionKey != NULL );
|
|
|
|
DBG_CASSERT( sizeof( pSourceBytes ) == sizeof( pSourceGuid ) );
|
|
pSourceBytes = reinterpret_cast<const char*>( pSourceGuid );
|
|
|
|
DBG_CASSERT( sizeof( pDestinationBytes ) == sizeof( pDestinationGuid ) );
|
|
pDestinationBytes = reinterpret_cast<char*>( pDestinationGuid );
|
|
|
|
DBG_CASSERT( sizeof( pEncryptionBytes ) == sizeof( pEncryptionKey ) );
|
|
pEncryptionBytes = reinterpret_cast<const char*>( pEncryptionKey );
|
|
|
|
DBG_CASSERT( ( sizeof( *pSourceGuid ) == sizeof( *pEncryptionKey ) ) &&
|
|
( sizeof( *pDestinationGuid ) == sizeof( *pEncryptionKey ) ) );
|
|
dwIndex = sizeof( *pSourceGuid );
|
|
while ( dwIndex != 0 )
|
|
{
|
|
dwIndex--;
|
|
pDestinationBytes[ dwIndex ] = pSourceBytes[ dwIndex ] ^ pEncryptionBytes[ dwIndex ];
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|