mirror of https://github.com/lianthony/NT4.0
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.
2792 lines
69 KiB
2792 lines
69 KiB
//****************************************************************************
|
|
//
|
|
// Module: Unimdm.tsp
|
|
// File: umdminit.c
|
|
// Content: This file contains the moudle initialization.
|
|
//
|
|
// Copyright (c) 1992-1993, Microsoft Corporation, all rights reserved
|
|
//
|
|
// History:
|
|
// Tue 23-Feb-1993 14:08:25 -by- Viroon Touranachun [viroont]
|
|
// Ported from TAPI's atsp
|
|
//
|
|
//****************************************************************************
|
|
|
|
#include "unimdm.h"
|
|
#include "umdmspi.h"
|
|
#include <regstr.h>
|
|
|
|
#include "common.h"
|
|
|
|
#define _INC_OLE
|
|
#include <ole2.h>
|
|
|
|
#define INITGUID
|
|
#include <initguid.h>
|
|
#include <devguid.h>
|
|
|
|
#include <setupapi.h>
|
|
|
|
#include <rovdbg.h>
|
|
|
|
//****************************************************************************
|
|
// Modem enumeration request
|
|
//****************************************************************************
|
|
|
|
typedef struct CountInfo{
|
|
UINT cModem;
|
|
} COUNTINFO, FAR* LPCOUNTINFO;
|
|
|
|
typedef struct InitInfo{
|
|
DWORD dwBaseID;
|
|
UINT cModem;
|
|
} INITINFO, FAR* LPINITINFO;
|
|
|
|
typedef struct FindInfo{
|
|
LPTSTR lpszDeviceName;
|
|
BOOL fFound;
|
|
HKEY FAR* lphkey;
|
|
LPTSTR lpszID;
|
|
UINT cbID;
|
|
} FINDINFO, FAR* LPFINDINFO;
|
|
|
|
|
|
typedef DWORD APIENTRY
|
|
PRIVATEGETDEFCOMMCONFIG(
|
|
HKEY hKey,
|
|
LPCOMMCONFIG pcc,
|
|
LPDWORD pdwSize
|
|
);
|
|
|
|
|
|
//****************************************************************************
|
|
// GLOBALS
|
|
//****************************************************************************
|
|
struct {
|
|
|
|
// Cache for hdevinfo, the handle returned by expensive function
|
|
// SetupDiGetClassDevsW.
|
|
HDEVINFO hdevinfo;
|
|
DWORD dwcRefHDevInfo;
|
|
|
|
// Cache for MODEMUI DLL and it's "PrivateDefCommConfig" export.
|
|
HINSTANCE hModemUIDLL;
|
|
DWORD dwcRefModemUI;
|
|
PRIVATEGETDEFCOMMCONFIG
|
|
*pfnPrivateDefCommConfig;
|
|
|
|
// Cache for whether current process has admin priveleges.
|
|
BOOL bAdminUser;
|
|
|
|
// Handle of thread that processes cpl notifications.
|
|
HANDLE hthrdCplNotif;
|
|
|
|
CRITICAL_SECTION crit;
|
|
|
|
CRITICAL_SECTION critCplNotif; // Critical section used ONLY to
|
|
//serialize launching the tepCplNotif thread.
|
|
} gUmdm;
|
|
|
|
|
|
// This is declared in unimdm.h, and is accessed by the MCX part as well.
|
|
DWORD gRegistryFlags;
|
|
|
|
#define USER_IS_ADMIN() (gUmdm.bAdminUser)
|
|
|
|
//****************************************************************************
|
|
// Constant Parameters
|
|
//****************************************************************************
|
|
|
|
LPGUID g_pguidModem = (LPGUID)&GUID_DEVCLASS_MODEM;
|
|
|
|
TCHAR cszFriendlyName[] = TEXT("FriendlyName");
|
|
TCHAR cszDeviceType[] = TEXT("DeviceType");
|
|
#ifdef VOICEVIEW
|
|
TCHAR cszVoiceView[] = TEXT("VoiceView");
|
|
#endif // VOICEVIEW
|
|
TCHAR cszID[] = TEXT("ID");
|
|
TCHAR cszProperties[] = TEXT("Properties");
|
|
TCHAR cszSettings[] = TEXT("Settings");
|
|
TCHAR cszDialSuffix[] = TEXT("DialSuffix");
|
|
TCHAR cszDevicePrefix[] = TEXT("\\\\.\\");
|
|
|
|
#define HAYES_COMMAND_LENGTH 40 // max size for DialSuffix (from VxD)
|
|
|
|
TCHAR cszHWNode[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E96D-E325-11CE-BFC1-08002BE10318}");
|
|
|
|
TCHAR gszTSPFilename[MAX_PATH];
|
|
|
|
|
|
#ifdef WINNT
|
|
extern CRITICAL_SECTION ServiceControlerCriticalSection;
|
|
#endif // WINNT
|
|
|
|
|
|
// Private function prototypes
|
|
//
|
|
|
|
LONG DevlineGetDefaultConfig(PLINEDEV pLineDev, HKEY hKey);
|
|
|
|
BOOL _ProcessAttach(HINSTANCE hDll);
|
|
BOOL _ProcessDetach(HINSTANCE hDll);
|
|
LONG DevlineEnum(LPDWORD lpdwNumLines);
|
|
LONG DevlineInitialize (DWORD dwBaseID, LPDWORD lpdwNumDevs);
|
|
LONG DevlineShutdown ();
|
|
void CleanupLineDev(PLINEDEV pLineDev);
|
|
PLINEDEV CreateLineDev(HKEY hKeyHardware, DWORD dwID, BOOL fReCreate);
|
|
BOOL PUBLIC IsAdminUser(void); // common code from ../rovcomm.lib
|
|
|
|
|
|
typedef BOOL (*ENUMMDMCALLBACK)(HKEY, LPVOID);
|
|
|
|
BOOL CountModemCallback (HKEY hkey, LPVOID lpData);
|
|
BOOL InitModemCallback (HKEY hkey, LPVOID lpData);
|
|
void FreeHDevInfo(HDEVINFO hdevinfo);
|
|
HDEVINFO GetHDevInfo(DWORD dwDIGCF);
|
|
BOOL LoadModemUI(void);
|
|
void UnloadModemUI(void);
|
|
void CplNotifComplete(BOOL fWait);
|
|
LONG EnumerateModems (ENUMMDMCALLBACK pfnCallback, LPVOID lpData, BOOL fAll);
|
|
|
|
typedef BOOL (*ENUMMDMKEYCALLBACK)(HKEY, LPTSTR, LPVOID);
|
|
|
|
BOOL SearchModemCallback (HKEY hkey, LPTSTR szKey, LPVOID lpData);
|
|
LONG EnumerateModemKeys (ENUMMDMKEYCALLBACK pfnCallback, LPVOID lpData);
|
|
|
|
LONG PASCAL ProviderInstall(LPTSTR pszProviderName, BOOL bNoMultipleInstance);
|
|
|
|
void tspInitGlobals(void);
|
|
void tspDeInitGlobals(void);
|
|
|
|
VOID WINAPI
|
|
UI_ProcessAttach(
|
|
VOID
|
|
);
|
|
|
|
VOID WINAPI
|
|
UI_ProcessDetach(
|
|
VOID
|
|
);
|
|
|
|
LONG WINAPI
|
|
StopModemDriver(
|
|
VOID
|
|
);
|
|
|
|
|
|
|
|
//****************************************************************************
|
|
// BOOL _Processattach (HINSTANCE)
|
|
//
|
|
// Function: This function is called when a process is attached to the DLL
|
|
//
|
|
// History:
|
|
// Mon 06-Sep-1993 09:20:10 -by- Viroon Touranachun [viroont]
|
|
// Ported from Shell.
|
|
//****************************************************************************
|
|
|
|
BOOL _ProcessAttach(HINSTANCE hDll)
|
|
{
|
|
BOOL fRet;
|
|
|
|
#ifdef DEBUG
|
|
// We do this simply to load the debug .ini flags
|
|
//
|
|
RovComm_ProcessIniFile();
|
|
|
|
DEBUG_BREAK(BF_ONPROCESSATT);
|
|
TRACE_MSG(TF_GENERAL, "Process Attach (hDll = %lx)", hDll);
|
|
#endif
|
|
InitializeCriticalSection(&gUmdm.crit);
|
|
InitializeCriticalSection(&gUmdm.critCplNotif);
|
|
|
|
traceOnProcessAttach();
|
|
|
|
UI_ProcessAttach();
|
|
|
|
// Initialize line device lists
|
|
//
|
|
fRet = InitCBList(hDll);
|
|
if (fRet)
|
|
{
|
|
// Remember our instance and module name
|
|
//
|
|
ghInstance = hDll;
|
|
GetModuleFileName(hDll,
|
|
gszTSPFilename,
|
|
sizeof(gszTSPFilename)/sizeof(TCHAR));
|
|
|
|
fRet = OverPoolInit();
|
|
|
|
if (!fRet)
|
|
{
|
|
DeinitCBList(hDll);
|
|
}
|
|
|
|
};
|
|
|
|
if (!fRet)
|
|
{
|
|
traceOnProcessDetach();
|
|
DeleteCriticalSection(&gUmdm.crit);
|
|
DeleteCriticalSection(&gUmdm.critCplNotif);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// BOOL _ProcessDetach (HINSTANCE)
|
|
//
|
|
// Function: This function is called when a process is detached from the DLL
|
|
//
|
|
// History:
|
|
// Mon 06-Sep-1993 09:20:10 -by- Viroon Touranachun [viroont]
|
|
// Ported from Shell.
|
|
//****************************************************************************
|
|
|
|
BOOL _ProcessDetach(HINSTANCE hDll)
|
|
{
|
|
DEBUG_CODE( TRACE_MSG(TF_GENERAL, "Process Detach (hDll = %lx)", hDll); )
|
|
DEBUG_CODE( DEBUG_BREAK(BF_ONPROCESSDET); )
|
|
|
|
// Clean up the allocated resources
|
|
//
|
|
DeinitCBList(hDll);
|
|
OverPoolDeinit();
|
|
UI_ProcessDetach();
|
|
ghInstance = NULL;
|
|
traceOnProcessDetach();
|
|
DeleteCriticalSection(&gUmdm.crit);
|
|
DeleteCriticalSection(&gUmdm.critCplNotif);
|
|
return TRUE;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// BOOL APIENTRY LibMain (HINSTANCE, DWORD, LPVOID)
|
|
//
|
|
// Function: This function is called when the DLL is loaded
|
|
//
|
|
// History:
|
|
// Mon 06-Sep-1993 09:20:10 -by- Viroon Touranachun [viroont]
|
|
// Ported from Shell.
|
|
//****************************************************************************
|
|
|
|
BOOL APIENTRY DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
|
|
{
|
|
switch(dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
_ProcessAttach(hDll);
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
_ProcessDetach(hDll);
|
|
break;
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
default:
|
|
break;
|
|
} // end switch()
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//****************************************************************************
|
|
//************************** The Initialization Calls*************************
|
|
//****************************************************************************
|
|
|
|
//****************************************************************************
|
|
// LONG
|
|
// TSPIAPI
|
|
// TSPI_providerInstall(
|
|
// HWND hwndOwner,
|
|
// DWORD dwPermanentProviderID
|
|
// )
|
|
//
|
|
// Function: Let's telephony CPL know the Remove function is supported.
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerInstall(
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
//
|
|
// Although this func is never called by TAPI v2.0, we export
|
|
// it so that the Telephony Control Panel Applet knows that it
|
|
// can add this provider via lineAddProvider(), otherwise
|
|
// Telephon.cpl will not consider it installable
|
|
//
|
|
//
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG
|
|
// TSPIAPI
|
|
// TSPI_providerRemove(
|
|
// HWND hwndOwner,
|
|
// DWORD dwPermanentProviderID
|
|
// )
|
|
//
|
|
// Function: Let's telephony CPL know the Install function is supported.
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerRemove(
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
//
|
|
// Although this func is never called by TAPI v2.0, we export
|
|
// it so that the Telephony Control Panel Applet knows that it
|
|
// can remove this provider via lineRemoveProvider(), otherwise
|
|
// Telephon.cpl will not consider it removable
|
|
//
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG
|
|
// TSPIAPI
|
|
// TSPI_providerConfig(
|
|
// HWND hwndOwner,
|
|
// DWORD dwPermanentProviderID
|
|
// )
|
|
//
|
|
// Function: Let's telephony CPL know the Config function is supported.
|
|
//
|
|
// History:
|
|
// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TSPI_providerConfig(
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
//
|
|
// Although this func is never called by TAPI v2.0, we export
|
|
// it so that the Telephony Control Panel Applet knows that it
|
|
// can configure this provider via lineConfigProvider(),
|
|
// otherwise Telephon.cpl will not consider it configurable
|
|
//
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG
|
|
// TSPIAPI
|
|
// TUISPI_providerInstall(
|
|
// TUISPIDLLCALLBACK lpfnUIDLLCallback,
|
|
// HWND hwndOwner,
|
|
// DWORD dwPermanentProviderID
|
|
// )
|
|
//
|
|
// Function: TSPI installation
|
|
//
|
|
// History:
|
|
// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo]
|
|
// Ported from TAPI's atsp
|
|
//****************************************************************************
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TUISPI_providerInstall(
|
|
TUISPIDLLCALLBACK lpfnUIDLLCallback,
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
return ProviderInstall (TEXT("unimdm.tsp"), TRUE);
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG
|
|
// TSPIAPI
|
|
// TUISPI_providerRemove(
|
|
// TUISPIDLLCALLBACK lpfnUIDLLCallback,
|
|
// HWND hwndOwner,
|
|
// DWORD dwPermanentProviderID
|
|
// )
|
|
//
|
|
// Function: TSPI removal
|
|
//
|
|
// History:
|
|
// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TUISPI_providerRemove(
|
|
TUISPIDLLCALLBACK lpfnUIDLLCallback,
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG
|
|
// TSPIAPI
|
|
// TUISPI_providerConfig(
|
|
// TUISPIDLLCALLBACK lpfnUIDLLCallback,
|
|
// HWND hwndOwner,
|
|
// DWORD dwPermanentProviderID
|
|
// )
|
|
//
|
|
// Function: TUISPI configuration
|
|
//
|
|
// History:
|
|
// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG
|
|
TSPIAPI
|
|
TUISPI_providerConfig(
|
|
TUISPIDLLCALLBACK lpfnUIDLLCallback,
|
|
HWND hwndOwner,
|
|
DWORD dwPermanentProviderID
|
|
)
|
|
{
|
|
WinExec("control.exe modem.cpl", SW_SHOW);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG TSPIAPI TSPI_providerEnumDevices()
|
|
//
|
|
// Function: TSPI device enumeration entry
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG TSPIAPI TSPI_providerEnumDevices(DWORD dwPermanentProviderID,
|
|
LPDWORD lpdwNumLines,
|
|
LPDWORD lpdwNumPhones,
|
|
HPROVIDER hProvider,
|
|
LINEEVENT lpfnLineCreateProc,
|
|
PHONEEVENT lpfnPhoneCreateProc)
|
|
|
|
{
|
|
DBG_ENTER_UL("TSPI_providerEnumDevices", dwPermanentProviderID);
|
|
|
|
TRACE3(
|
|
IDEVENT_TSPFN_ENTER,
|
|
IDFROM_TSPI_providerEnumDevices,
|
|
&dwPermanentProviderID
|
|
);
|
|
|
|
// Enumerate the number of device
|
|
//
|
|
DevlineEnum(lpdwNumLines);
|
|
*lpdwNumPhones = 0;
|
|
|
|
// Initialize the global parameters
|
|
//
|
|
gfnLineCreateProc = lpfnLineCreateProc;
|
|
gdwProviderID = dwPermanentProviderID;
|
|
ghProvider = hProvider;
|
|
|
|
TRACE4(IDEVENT_TSPFN_EXIT,
|
|
IDFROM_TSPI_providerEnumDevices,
|
|
&dwPermanentProviderID,
|
|
ERROR_SUCCESS);
|
|
|
|
DBG_EXIT_UL("TSPI_providerEnumDevices", ERROR_SUCCESS);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG TSPIAPI TSPI_providerInit(DWORD dwTSPIVersion, DWORD ppid)
|
|
//
|
|
// Function: Initializes the global data strucutres.
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG TSPIAPI TSPI_providerInit(DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID,
|
|
DWORD dwLineDeviceIDBase,
|
|
DWORD dwPhoneDeviceIDBase,
|
|
DWORD dwNumLines,
|
|
DWORD dwNumPhones,
|
|
ASYNC_COMPLETION cbCompletionProc,
|
|
LPDWORD lpdwTSPIOptions)
|
|
{
|
|
DWORD dwDevicePorts = 0; // Number of modem devices
|
|
DWORD retcode ;
|
|
BOOL fModemUILoaded=FALSE;
|
|
HDEVINFO hdevinfo=NULL;
|
|
|
|
DBG_ENTER_UL("TSPI_providerInit", dwPermanentProviderID);
|
|
|
|
// Initialize tracing facilities
|
|
//
|
|
traceInitialize(dwPermanentProviderID);
|
|
|
|
TRACE3(
|
|
IDEVENT_TSPFN_ENTER,
|
|
IDFROM_TSPI_providerInit,
|
|
&dwTSPIVersion
|
|
);
|
|
|
|
ASSERT(gdwProviderID == dwPermanentProviderID);
|
|
|
|
|
|
|
|
// Initialize the global parameters
|
|
//
|
|
tspInitGlobals();
|
|
|
|
// Load MODEMUI.DLL (for private entry points)
|
|
fModemUILoaded=TRUE;
|
|
if (!LoadModemUI())
|
|
{
|
|
fModemUILoaded=FALSE;
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
// For the modem device, get the device information
|
|
hdevinfo = GetHDevInfo(DIGCF_PRESENT);
|
|
if (!hdevinfo)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
if (TRACINGENABLED())
|
|
{
|
|
cbCompletionProc = traceSetCompletionProc(cbCompletionProc);
|
|
}
|
|
|
|
gfnCompletionCallback = cbCompletionProc;
|
|
|
|
//
|
|
// init common modem info list
|
|
//
|
|
InitializeModemCommonList(
|
|
&gCommonList
|
|
);
|
|
|
|
InitializeCriticalSection(
|
|
&ServiceControlerCriticalSection
|
|
);
|
|
|
|
|
|
|
|
// Initialize the line structures
|
|
//
|
|
retcode = DevlineInitialize(dwLineDeviceIDBase, &dwDevicePorts);
|
|
|
|
if (retcode != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// cleanup common modem info
|
|
//
|
|
RemoveCommonList(
|
|
&gCommonList
|
|
);
|
|
|
|
DeleteCriticalSection(
|
|
&ServiceControlerCriticalSection
|
|
);
|
|
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
if (hdevinfo != NULL) {
|
|
|
|
FreeHDevInfo(hdevinfo);
|
|
}
|
|
|
|
if(fModemUILoaded)
|
|
{
|
|
UnloadModemUI();
|
|
}
|
|
|
|
TRACE4(
|
|
IDEVENT_TSPFN_EXIT,
|
|
IDFROM_TSPI_providerInit,
|
|
&dwTSPIVersion,
|
|
retcode
|
|
);
|
|
|
|
if (retcode != ERROR_SUCCESS)
|
|
{
|
|
// Deinit tracing
|
|
//
|
|
traceDeinitialize();
|
|
}
|
|
|
|
DBG_EXIT_UL("TSPI_providerInit", retcode);
|
|
return retcode;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG TSPIAPI TSPI_providerShutdown(DWORD dwTSPIVersion)
|
|
//
|
|
// Function: Cleans up all the global data structures.
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG TSPIAPI TSPI_providerShutdown(DWORD dwTSPIVersion,
|
|
DWORD dwPermanentProviderID)
|
|
{
|
|
DBG_ENTER_UL("TSPI_providerShutdown", dwTSPIVersion);
|
|
|
|
TRACE3(
|
|
IDEVENT_TSPFN_ENTER,
|
|
IDFROM_TSPI_providerShutdown,
|
|
&dwTSPIVersion
|
|
);
|
|
|
|
#ifdef DYNA_ADDREMOVE
|
|
// Complete any re-enumeration that may be in progress..
|
|
//
|
|
CplNotifComplete(TRUE);
|
|
#endif // DYNA_ADDREMOVE
|
|
|
|
// Clean up modem lines
|
|
//
|
|
DevlineShutdown();
|
|
|
|
|
|
//
|
|
// cleanup common modem info
|
|
//
|
|
RemoveCommonList(
|
|
&gCommonList
|
|
);
|
|
|
|
// Clean up the global parameters
|
|
//
|
|
gfnCompletionCallback = NULL; // The async completion callback
|
|
gfnLineCreateProc = NULL;
|
|
|
|
StopModemDriver();
|
|
|
|
DeleteCriticalSection(
|
|
&ServiceControlerCriticalSection
|
|
);
|
|
|
|
TRACE4(
|
|
IDEVENT_TSPFN_EXIT,
|
|
IDFROM_TSPI_providerShutdown,
|
|
&dwTSPIVersion,
|
|
ERROR_SUCCESS
|
|
);
|
|
|
|
// DeInit TSP Globals
|
|
tspDeInitGlobals();
|
|
|
|
// Deinit tracing
|
|
//
|
|
traceDeinitialize();
|
|
|
|
DBG_EXIT_UL("TSPI_providerShutdown", ERROR_SUCCESS);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG TSPIAPI TSPI_lineNegotiateTSPIVersion()
|
|
//
|
|
// Function: Negotiates the service provider version.
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG TSPIAPI TSPI_lineNegotiateTSPIVersion(DWORD dwDeviceID,
|
|
DWORD dwLowVersion,
|
|
DWORD dwHighVersion,
|
|
LPDWORD lpdwTSPIVersion)
|
|
{
|
|
PLINEDEV pLineDev = NULL;
|
|
LONG lRet = LINEERR_OPERATIONFAILED; // assume failure
|
|
|
|
DBG_DDI_ENTER("TSPI_lineNegotiateTSPIVersion");
|
|
|
|
TRACE3(
|
|
IDEVENT_TSPFN_ENTER,
|
|
IDFROM_TSPI_lineNegotiateTSPIVersion,
|
|
&dwDeviceID
|
|
);
|
|
// Check the range of the device ID
|
|
//
|
|
if((dwDeviceID == INITIALIZE_NEGOTIATION) ||
|
|
((pLineDev = GetCBfromID(dwDeviceID)) != NULL))
|
|
{
|
|
// Do not use the line device
|
|
//
|
|
if (pLineDev)
|
|
{
|
|
RELEASE_LINEDEV(pLineDev);
|
|
}
|
|
|
|
// Check the version range
|
|
//
|
|
if((dwLowVersion > MDMSPI_VERSION) || (dwHighVersion < MDMSPI_VERSION))
|
|
{
|
|
*lpdwTSPIVersion = 0;
|
|
lRet= LINEERR_INCOMPATIBLEAPIVERSION;
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
*lpdwTSPIVersion = MDMSPI_VERSION;
|
|
lRet= ERROR_SUCCESS;
|
|
goto end;
|
|
};
|
|
};
|
|
|
|
// The requested device doesn't exist.
|
|
lRet = LINEERR_NODEVICE;
|
|
|
|
end:
|
|
|
|
TRACE4(
|
|
IDEVENT_TSPFN_EXIT,
|
|
IDFROM_TSPI_lineNegotiateTSPIVersion,
|
|
&dwDeviceID,
|
|
lRet
|
|
);
|
|
DBG_DDI_EXIT("TSPI_lineNegotiateTSPIVersion", lRet);
|
|
|
|
return lRet;
|
|
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG DevlineEnum()
|
|
//
|
|
// Function: enumerates the current number of modems
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG DevlineEnum(LPDWORD lpdwNumLines)
|
|
{
|
|
COUNTINFO ci;
|
|
DWORD dwRet;
|
|
|
|
ci.cModem = 0;
|
|
|
|
if ((dwRet = EnumerateModems(CountModemCallback, (LPVOID)&ci, FALSE)) == ERROR_SUCCESS)
|
|
*lpdwNumLines = ci.cModem;
|
|
else
|
|
*lpdwNumLines = 0;
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG DevlineInitialize()
|
|
//
|
|
// Function: initializes the modem device list
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG DevlineInitialize (DWORD dwBaseID,
|
|
LPDWORD lpdwNumDevs)
|
|
{
|
|
INITINFO initi;
|
|
DWORD dwRet;
|
|
|
|
initi.dwBaseID = dwBaseID;
|
|
initi.cModem = 0;
|
|
|
|
|
|
MdmInitTracing();
|
|
|
|
dwRet = EnumerateModems(InitModemCallback, (LPVOID)&initi, FALSE);
|
|
if (dwRet == ERROR_SUCCESS)
|
|
{
|
|
*lpdwNumDevs = initi.cModem;
|
|
// Initialize Timer services
|
|
//
|
|
if ((dwRet = InitializeMdmTimer()) == ERROR_SUCCESS)
|
|
{
|
|
// Initialize the asynchronous thread
|
|
//
|
|
if ((dwRet = InitializeMdmThreads()) != ERROR_SUCCESS)
|
|
{
|
|
DeinitializeMdmTimer();
|
|
};
|
|
};
|
|
}
|
|
else
|
|
*lpdwNumDevs = 0;
|
|
|
|
if (dwRet!=ERROR_SUCCESS)
|
|
{
|
|
MdmDeinitTracing();
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG DevlineShutdown()
|
|
//
|
|
// Function: destroys the modem device list and resources
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//****************************************************************************
|
|
|
|
LONG DevlineShutdown ()
|
|
{
|
|
PLINEDEV pLineDev;
|
|
|
|
// Deinitialize the modem thread
|
|
//
|
|
DeinitializeMdmThreads();
|
|
DeinitializeMdmTimer();
|
|
|
|
// Destroy the modem line device one at a time.
|
|
//
|
|
do
|
|
{
|
|
// If there is another modem to clean up
|
|
//
|
|
if ((pLineDev = GetFirstCB()) != NULL)
|
|
{
|
|
// Clean up the allocated resources
|
|
//
|
|
CleanupLineDev(pLineDev);
|
|
RELEASE_LINEDEV(pLineDev);
|
|
|
|
// Now delete the modem device
|
|
//
|
|
DeleteCB(pLineDev);
|
|
};
|
|
}
|
|
while (pLineDev != NULL);
|
|
|
|
MdmDeinitTracing();
|
|
|
|
return ERROR_SUCCESS ;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// void CleanupLineDev(PLINEDEV)
|
|
//
|
|
// Function: Frees the resources owned by the modem line device.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//
|
|
//****************************************************************************
|
|
|
|
void CleanupLineDev(PLINEDEV pLineDev)
|
|
{
|
|
int i;
|
|
|
|
if (pLineDev->DroppingEvent != NULL) {
|
|
|
|
CloseHandle(pLineDev->DroppingEvent);
|
|
|
|
pLineDev->DroppingEvent=NULL;
|
|
}
|
|
|
|
// Clean up the allocated resources
|
|
//
|
|
if (pLineDev->hIcon != NULL)
|
|
{
|
|
DestroyIcon(pLineDev->hIcon);
|
|
};
|
|
|
|
if (pLineDev->pDevCfg != NULL) {
|
|
|
|
LocalFree((HLOCAL)pLineDev->pDevCfg);
|
|
|
|
pLineDev->pDevCfg=NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//****************************************************************************
|
|
// PLINEDEV CreateLineDev(HKEY hKey, DWORD dwID, BOOL fReCreate)
|
|
//
|
|
// Function: Create a new LINEDEV structure and initilaizes it.
|
|
// If fReCreate is TRUE, the following happens:
|
|
// -- if it exists, it will return NULL, but will set the
|
|
// LINEDEVFLAGS_REINIT flag of pLineDev->fdwResources of
|
|
// the existing device.
|
|
// -- if it does not exist, it will create it, and also set
|
|
// the above flag.
|
|
// If fReCreate is FALSE, it will not check if the device exists
|
|
// and will NOT set the LINEDEVFAGS_REINIT bit.
|
|
//
|
|
// Returns: a pointer to the new line device CB on success or
|
|
// NULL on failure.
|
|
//
|
|
// History:
|
|
// Mon 17-Apr-1995 11:49:53 -by- Viroon Touranachun [viroont]
|
|
// Ported from Win95.
|
|
//
|
|
//****************************************************************************
|
|
|
|
PLINEDEV CreateLineDev(HKEY hKey, DWORD dwID, BOOL fReCreate)
|
|
{
|
|
PLINEDEV pLineDev=NULL;
|
|
TCHAR rgtchDeviceName[sizeof(pLineDev->szDeviceName)/sizeof(TCHAR)];
|
|
DWORD dwRegSize = sizeof(rgtchDeviceName);
|
|
DWORD dwRegType;
|
|
DWORD dwRet;
|
|
BYTE bDeviceType;
|
|
REGDEVCAPS regdevcaps;
|
|
HKEY hKeySettings;
|
|
int i;
|
|
FINDINFO fi;
|
|
TCHAR pszTemp[HAYES_COMMAND_LENGTH+1];
|
|
|
|
|
|
// Get the Friendly Name
|
|
ASSERT(dwRegSize == sizeof(pLineDev->szDeviceName));
|
|
dwRet = RegQueryValueEx(
|
|
hKey,
|
|
cszFriendlyName,
|
|
NULL,
|
|
&dwRegType,
|
|
(VOID *) rgtchDeviceName,
|
|
&dwRegSize
|
|
);
|
|
|
|
if (dwRet != ERROR_SUCCESS || dwRegType != REG_SZ)
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
#ifdef DYNA_ADDREMOVE
|
|
if (fReCreate)
|
|
{
|
|
// determine if we've already got this device in our list...
|
|
pLineDev = GetCBfromName (rgtchDeviceName);
|
|
if (pLineDev)
|
|
{
|
|
DPRINTF1("ReCreate: Modem exists: %s", rgtchDeviceName);
|
|
pLineDev->fdwResources |= LINEDEVFLAGS_REINIT;
|
|
pLineDev->fdwResources &= ~LINEDEVFLAGS_OUTOFSERVICE;
|
|
RELEASE_LINEDEV(pLineDev);
|
|
pLineDev=NULL;
|
|
goto end;
|
|
}
|
|
}
|
|
#endif //DYNA_ADDREMOVE
|
|
|
|
// New modem!
|
|
|
|
if ((pLineDev = AllocateCB(sizeof(LINEDEV))) == NULL)
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
pLineDev->DroppingEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
if (pLineDev->DroppingEvent == NULL) {
|
|
|
|
goto FailedExit;
|
|
}
|
|
|
|
// Initialize its control block
|
|
//
|
|
// pLineDev->hIcon = NULL;
|
|
// pLineDev->pDevCfg = NULL;
|
|
//
|
|
pLineDev->dwVersion = UMDM_VERSION;
|
|
pLineDev->dwID = dwID;
|
|
lstrcpy(pLineDev->szDeviceName, rgtchDeviceName);
|
|
|
|
// Get the Driver Key
|
|
fi.lpszDeviceName = pLineDev->szDeviceName;
|
|
fi.fFound = FALSE;
|
|
fi.lphkey = NULL;
|
|
fi.lpszID = pszTemp;
|
|
fi.cbID = sizeof(pszTemp);
|
|
EnumerateModemKeys(SearchModemCallback, (LPVOID)&fi);
|
|
if (!fi.fFound)
|
|
{
|
|
goto FailedExit;
|
|
}
|
|
|
|
lstrcpyn(pLineDev->szDriverKey, cszHWNode, sizeof(pLineDev->szDriverKey));
|
|
lstrcat(pLineDev->szDriverKey, TEXT("\\"));
|
|
lstrcat(pLineDev->szDriverKey, pszTemp);
|
|
|
|
// Read in the permanent ID
|
|
dwRegSize = sizeof(pLineDev->dwPermanentLineID);
|
|
if (RegQueryValueEx(hKey, cszID, NULL, &dwRegType,
|
|
(VOID *)&pLineDev->dwPermanentLineID,
|
|
&dwRegSize) != ERROR_SUCCESS ||
|
|
dwRegType != REG_BINARY)
|
|
{
|
|
goto FailedExit;
|
|
}
|
|
|
|
// Read in the REGDEVCAPS
|
|
dwRegSize = sizeof(regdevcaps);
|
|
if (RegQueryValueEx(hKey, cszProperties, NULL, &dwRegType,
|
|
(VOID *)®devcaps,
|
|
&dwRegSize) != ERROR_SUCCESS ||
|
|
dwRegType != REG_BINARY)
|
|
{
|
|
goto FailedExit;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We want to make sure the following flags are identical
|
|
//
|
|
#if (LINEDEVCAPFLAGS_DIALBILLING != DIALOPTION_BILLING)
|
|
#error LINEDEVCAPFLAGS_DIALBILLING != DIALOPTION_BILLING (check tapi.h vs. mcx16.h)
|
|
#endif
|
|
#if (LINEDEVCAPFLAGS_DIALQUIET != DIALOPTION_QUIET)
|
|
#error LINEDEVCAPFLAGS_DIALQUIET != DIALOPTION_QUIET (check tapi.h vs. mcx16.h)
|
|
#endif
|
|
#if (LINEDEVCAPFLAGS_DIALDIALTONE != DIALOPTION_DIALTONE)
|
|
#error LINEDEVCAPFLAGS_DIALDIALTONE != DIALOPTION_DIALTONE (check tapi.h vs. mcx16.h)
|
|
#endif
|
|
//
|
|
|
|
// Make sure this is the dwDialOptions DWORD we want.
|
|
ASSERT(!(regdevcaps.dwDialOptions & ~(LINEDEVCAPFLAGS_DIALBILLING |
|
|
LINEDEVCAPFLAGS_DIALQUIET |
|
|
LINEDEVCAPFLAGS_DIALDIALTONE)));
|
|
pLineDev->dwDevCapFlags = regdevcaps.dwDialOptions;
|
|
|
|
pLineDev->dwMaxDCERate = regdevcaps.dwMaxDCERate;
|
|
|
|
pLineDev->dwModemOptions = regdevcaps.dwModemOptions;
|
|
}
|
|
|
|
// Analyze device type and set mediamodes appropriately
|
|
dwRegSize = sizeof(BYTE);
|
|
if (RegQueryValueEx(hKey, cszDeviceType, NULL, &dwRegType,
|
|
&bDeviceType, &dwRegSize) != ERROR_SUCCESS ||
|
|
dwRegType != REG_BINARY ||
|
|
dwRegSize != sizeof(BYTE))
|
|
{
|
|
goto FailedExit;
|
|
}
|
|
else
|
|
{
|
|
// Remember the type
|
|
//
|
|
pLineDev->bDeviceType = bDeviceType;
|
|
|
|
switch (bDeviceType)
|
|
{
|
|
case DT_PARALLEL_PORT:
|
|
pLineDev->bDeviceType = DT_NULL_MODEM; // Map back to null modem
|
|
// FALLTHROUGH
|
|
|
|
case DT_NULL_MODEM:
|
|
pLineDev->dwDefaultMediaModes = LINEMEDIAMODE_DATAMODEM;
|
|
pLineDev->dwBearerModes = LINEBEARERMODE_DATA | LINEBEARERMODE_PASSTHROUGH;
|
|
pLineDev->fPartialDialing = FALSE;
|
|
break;
|
|
|
|
case DT_PARALLEL_MODEM:
|
|
pLineDev->bDeviceType = DT_EXTERNAL_MODEM; // Map back to external modem
|
|
// FALLTHROUGH
|
|
|
|
case DT_EXTERNAL_MODEM:
|
|
case DT_INTERNAL_MODEM:
|
|
case DT_PCMCIA_MODEM:
|
|
pLineDev->dwDefaultMediaModes = LINEMEDIAMODE_DATAMODEM |
|
|
LINEMEDIAMODE_INTERACTIVEVOICE;
|
|
#ifdef VOICEVIEW
|
|
{
|
|
BYTE bVoiceView;
|
|
|
|
dwRegSize = 1;
|
|
if ((RegQueryValueEx(hKeySoftware, cszVoiceView, 0, &dwRegType, &bVoiceView, &dwRegSize) == ERROR_SUCCESS) &&
|
|
(bVoiceView == 1))
|
|
{
|
|
pLineDev->dwDefaultMediaModes |= LINEMEDIAMODE_VOICEVIEW;
|
|
}
|
|
}
|
|
#endif // VOICEVIEW
|
|
pLineDev->dwBearerModes = LINEBEARERMODE_VOICE | LINEBEARERMODE_PASSTHROUGH;
|
|
|
|
// read in Settings\DialSuffix to check whether we can partial dial
|
|
pLineDev->fPartialDialing = FALSE; // assume false
|
|
if (RegOpenKey(hKey, cszSettings, &hKeySettings) == ERROR_SUCCESS)
|
|
{
|
|
dwRegSize = HAYES_COMMAND_LENGTH;
|
|
if (RegQueryValueEx(hKeySettings, cszDialSuffix, NULL, &dwRegType, (VOID *)pszTemp, &dwRegSize) == ERROR_SUCCESS &&
|
|
dwRegSize > sizeof(TCHAR))
|
|
{
|
|
pLineDev->fPartialDialing = TRUE;
|
|
}
|
|
RegCloseKey(hKeySettings);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
goto FailedExit;
|
|
}
|
|
}
|
|
|
|
// Init line.
|
|
NullifyLineDevice(pLineDev);
|
|
|
|
//
|
|
// get the default commconfig
|
|
//
|
|
dwRet = DevlineGetDefaultConfig(pLineDev,hKey);
|
|
|
|
if (dwRet != ERROR_SUCCESS) {
|
|
|
|
goto FailedExit;
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNDER_CONSTRUCTION
|
|
|
|
// Check the devnode status
|
|
// If it does not exist or has a problem, mark it as out of service
|
|
//
|
|
if (!IsDeviceInService(szID))
|
|
{
|
|
pLineDev->fdwResources |= LINEDEVFLAGS_OUTOFSERVICE;
|
|
};
|
|
|
|
#endif // UNDER_CONSTRUCTION
|
|
|
|
if (fReCreate)
|
|
{
|
|
pLineDev->fdwResources |= LINEDEVFLAGS_REINIT;
|
|
}
|
|
|
|
// We made it this far, we're GOLDEN!
|
|
goto end;
|
|
|
|
FailedExit:
|
|
DPRINTF("Modem unusable because of corrupt registry entry.");
|
|
|
|
// Cleanup the allocated resource
|
|
//
|
|
CleanupLineDev(pLineDev);
|
|
|
|
// Free the modem CB and its resources
|
|
//
|
|
DeleteCB(pLineDev);
|
|
pLineDev = NULL;
|
|
// Fall through...
|
|
|
|
end:
|
|
|
|
return pLineDev;
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// LONG DevlineGetDefaultConfig(PLINEDEV)
|
|
//
|
|
// Function: Get modem default configuratio
|
|
//
|
|
// Returns: ERROR_SUCCESS if success
|
|
// LINEERR_NOMEM if out of memory
|
|
//
|
|
// Fri 14-Apr-1995 12:47:26 -by- Viroon Touranachun [viroont]
|
|
// created
|
|
//****************************************************************************
|
|
|
|
LONG DevlineGetDefaultConfig(PLINEDEV pLineDev, HKEY hKey)
|
|
{
|
|
PDEVCFG pDevCfg;
|
|
COMMCONFIG * pcommconfig;
|
|
DWORD dwCCSize;
|
|
LONG lResult;
|
|
|
|
dwCCSize = sizeof(MODEMSETTINGS)+FIELDOFFSET(COMMCONFIG, wcProviderData);
|
|
|
|
pDevCfg = (PDEVCFG)LocalAlloc(LPTR, sizeof(DEVCFGHDR)+(UINT)dwCCSize);
|
|
|
|
if (pDevCfg == NULL) {
|
|
|
|
return LINEERR_NOMEM;
|
|
}
|
|
|
|
pcommconfig = (COMMCONFIG *)&(pDevCfg->commconfig);
|
|
|
|
// Default setting
|
|
//
|
|
pDevCfg->dfgHdr.dwSize = sizeof(DEVCFGHDR) + dwCCSize;
|
|
pDevCfg->dfgHdr.dwVersion = MDMCFG_VERSION;
|
|
SETWAITBONG(pDevCfg, DEF_WAIT_BONG);
|
|
SETOPTIONS(pDevCfg, (IS_NULL_MODEM(pLineDev) ?
|
|
TERMINAL_NONE : TERMINAL_NONE | LAUNCH_LIGHTS));
|
|
pcommconfig->dwProviderSubType = PST_MODEM;
|
|
|
|
ASSERT(gUmdm.pfnPrivateDefCommConfig != NULL);
|
|
|
|
lResult=(*gUmdm.pfnPrivateDefCommConfig)(hKey, pcommconfig, &dwCCSize);
|
|
|
|
if (ERROR_SUCCESS == lResult) {
|
|
|
|
pLineDev->pDevCfg = pDevCfg;
|
|
|
|
} else {
|
|
|
|
LocalFree(
|
|
pDevCfg
|
|
);
|
|
}
|
|
|
|
|
|
return lResult;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//****************************************************************************
|
|
// BOOL CountModemCallback (HKEY hkey, LPVOID lpData)
|
|
//
|
|
// Function: Count the enumerated modems.
|
|
//
|
|
// Returns: TRUE always to continue
|
|
//
|
|
//****************************************************************************
|
|
|
|
BOOL CountModemCallback (HKEY hkey, LPVOID lpData)
|
|
{
|
|
LPCOUNTINFO lpCntInfo = (LPCOUNTINFO)lpData;
|
|
|
|
(lpCntInfo->cModem)++;
|
|
return TRUE;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// BOOL InitModemCallback (HKEY hkey, LPVOID lpData)
|
|
//
|
|
// Function: Initialize the enumerated modems.
|
|
//
|
|
// Returns: TRUE always to continue
|
|
//
|
|
//****************************************************************************
|
|
|
|
BOOL InitModemCallback (HKEY hkey, LPVOID lpData)
|
|
{
|
|
PLINEDEV pMdmDev;
|
|
LPINITINFO lpInitInfo = (LPINITINFO)lpData;
|
|
|
|
if ((pMdmDev = CreateLineDev(hkey,
|
|
lpInitInfo->dwBaseID +
|
|
lpInitInfo->cModem,
|
|
FALSE)) != NULL)
|
|
{
|
|
// Insert into the LINEDEV list
|
|
//
|
|
AddCBToList(pMdmDev);
|
|
(lpInitInfo->cModem)++;
|
|
};
|
|
return TRUE;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// EnumerateModems()
|
|
//
|
|
// Function: Enumerate the modem.
|
|
//
|
|
//****************************************************************************
|
|
|
|
LONG NEAR PASCAL EnumerateModems (ENUMMDMCALLBACK pfnCallback,
|
|
LPVOID lpData,
|
|
BOOL fAll)
|
|
{
|
|
HDEVINFO hdevinfo;
|
|
SP_DEVINFO_DATA diData;
|
|
DWORD iEnum;
|
|
BOOL fContinue;
|
|
HKEY hkey;
|
|
DWORD dwRW = KEY_READ;
|
|
// DWORD dwDIGCF = (fAll) ? DIGCF_PROFILE : DIGCF_PRESENT;
|
|
BOOL fFreeDevInfo=FALSE;
|
|
DWORD dwDIGCF = DIGCF_PRESENT;
|
|
if (USER_IS_ADMIN()) dwRW |= KEY_WRITE;
|
|
|
|
// Get the device info set
|
|
//
|
|
hdevinfo = GetHDevInfo(dwDIGCF);
|
|
|
|
if (hdevinfo != NULL)
|
|
{
|
|
// Enumerate each modem
|
|
//
|
|
fFreeDevInfo=TRUE;
|
|
fContinue = TRUE;
|
|
iEnum = 0;
|
|
diData.cbSize = sizeof(diData);
|
|
while(fContinue && SetupDiEnumDeviceInfo(hdevinfo, iEnum, &diData))
|
|
{
|
|
// Get the driver key
|
|
//
|
|
hkey = SetupDiOpenDevRegKey(hdevinfo, &diData, DICS_FLAG_GLOBAL, 0,
|
|
DIREG_DRV, dwRW);
|
|
if (hkey == INVALID_HANDLE_VALUE)
|
|
{
|
|
DPRINTF1(
|
|
"SetupDiOpenDevRegKeyfailed, err=0x%lx",
|
|
GetLastError()
|
|
);
|
|
}
|
|
else
|
|
{
|
|
fContinue = (*pfnCallback)(hkey, lpData);
|
|
|
|
RegCloseKey(hkey);
|
|
};
|
|
|
|
// Find next modem
|
|
//
|
|
iEnum++;
|
|
};
|
|
FreeHDevInfo(hdevinfo);
|
|
};
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
//****************************************************************************
|
|
// BOOL SearchModemCallback (HKEY hkey, LPTSTR szKey, LPVOID lpData)
|
|
//
|
|
// Function: Search the enumerated modems for a matching modem.
|
|
//
|
|
// Returns: TRUE if not match and continue searching
|
|
//
|
|
//****************************************************************************
|
|
|
|
BOOL SearchModemCallback (HKEY hkey, LPTSTR szKey, LPVOID lpData)
|
|
{
|
|
LPFINDINFO lpFindInfo = (LPFINDINFO)lpData;
|
|
TCHAR szDevice[MAXDEVICENAME+1];
|
|
DWORD dwRegType, dwRegSize;
|
|
BOOL fContinue = TRUE;
|
|
|
|
// Get the Friendly Name
|
|
//
|
|
dwRegSize = sizeof(szDevice);
|
|
if ((RegQueryValueEx(hkey, cszFriendlyName, NULL,
|
|
&dwRegType, (VOID *)szDevice, &dwRegSize)
|
|
== ERROR_SUCCESS) && (dwRegType == REG_SZ))
|
|
{
|
|
// Is this the device?
|
|
//
|
|
if (!lstrcmpi(lpFindInfo->lpszDeviceName, szDevice))
|
|
{
|
|
// BUG! BUG! the key will be closed
|
|
//
|
|
if (lpFindInfo->lphkey != NULL)
|
|
{
|
|
*lpFindInfo->lphkey = hkey;
|
|
};
|
|
|
|
// Do we need the Instance ID?
|
|
//
|
|
if ((lpFindInfo->lpszID != NULL) &&
|
|
(lpFindInfo->cbID > 0))
|
|
{
|
|
// Return the instance ID
|
|
//
|
|
lstrcpyn(lpFindInfo->lpszID, szKey,
|
|
lpFindInfo->cbID);
|
|
};
|
|
|
|
// Mark that we found it
|
|
lpFindInfo->fFound = TRUE;
|
|
fContinue = FALSE;
|
|
};
|
|
};
|
|
return fContinue;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// EnumerateModemKeys()
|
|
//
|
|
// Function: Enumerate the modem driver key.
|
|
//
|
|
//****************************************************************************
|
|
|
|
LONG NEAR PASCAL EnumerateModemKeys (ENUMMDMKEYCALLBACK pfnCallback,
|
|
LPVOID lpData)
|
|
{
|
|
HKEY hkey, hkeyEnumNode;
|
|
UINT iEnum;
|
|
TCHAR szEnumNode[REGSTR_MAX_VALUE_LENGTH+1];
|
|
BOOL fTerminate;
|
|
DWORD dwRegType, dwRegSize;
|
|
|
|
// Initialize the global enumeration parameters
|
|
//
|
|
fTerminate = FALSE;
|
|
|
|
// Get the key to the modem hardware node
|
|
if (RegOpenKey(HKEY_LOCAL_MACHINE, cszHWNode, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
// Enumerate the enumerator
|
|
iEnum = 0;
|
|
while ((!fTerminate) &&
|
|
(RegEnumKey(hkey, iEnum, szEnumNode,
|
|
sizeof(szEnumNode)) == ERROR_SUCCESS ))
|
|
{
|
|
// Open the modem node for this enumerator
|
|
if (RegOpenKey(hkey, szEnumNode, &hkeyEnumNode) == ERROR_SUCCESS)
|
|
{
|
|
// Allow the callback function to do their stuff
|
|
fTerminate = !(*pfnCallback)(hkeyEnumNode, szEnumNode, lpData);
|
|
|
|
RegCloseKey(hkeyEnumNode);
|
|
};
|
|
iEnum++;
|
|
};
|
|
RegCloseKey(hkey);
|
|
};
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// LONG
|
|
// PASCAL
|
|
// ProviderInstall(
|
|
// LPTSTR pszProviderName,
|
|
// BOOL bNoMultipleInstance
|
|
// )
|
|
//
|
|
// Function: Check to see if a service provider is already installed. Returns
|
|
// appropriate TSPI error code to be passed back from
|
|
// TUISPI_providerInstall.
|
|
//
|
|
// History:
|
|
// Thu 21-Dec-1995 18:24:53 -by- Chris Caputo [ccaputo]
|
|
// Ported from TAPI's atsp32. Periodically, make sure it is in sync to catch
|
|
// any bugs fixed in that code.
|
|
//****************************************************************************
|
|
|
|
LONG
|
|
PASCAL
|
|
ProviderInstall(
|
|
LPTSTR pszProviderName,
|
|
BOOL bNoMultipleInstance
|
|
)
|
|
{
|
|
LONG lResult;
|
|
|
|
|
|
//
|
|
// If only one installation instance of this provider is
|
|
// allowed then we want to check the provider list to see
|
|
// if the provider is already installed
|
|
//
|
|
|
|
if (bNoMultipleInstance)
|
|
{
|
|
LONG (WINAPI *pfnGetProviderList)();
|
|
DWORD dwTotalSize, i;
|
|
HINSTANCE hTapi32;
|
|
LPLINEPROVIDERLIST pProviderList;
|
|
LPLINEPROVIDERENTRY pProviderEntry;
|
|
|
|
|
|
lResult = LINEERR_OPERATIONFAILED; // assume failure
|
|
|
|
|
|
//
|
|
// Load Tapi32.dll & get a pointer to the lineGetProviderList
|
|
// func. We could just statically link with Tapi32.lib and
|
|
// avoid the hassle (and this wouldn't have any adverse
|
|
// performance effects because of the fact that this
|
|
// implementation has a separate ui dll that runs only on the
|
|
// client context), but a provider who implemented these funcs
|
|
// in it's TSP module would want to do an explicit load like
|
|
// we do here to prevent the perf hit of Tapi32.dll always
|
|
// getting loaded in Tapisrv.exe's context.
|
|
//
|
|
|
|
if (!(hTapi32 = LoadLibrary (TEXT("tapi32.dll"))))
|
|
{
|
|
DPRINTF1(
|
|
"LoadLibrary(tapi32.dll) failed, err=%d",
|
|
GetLastError()
|
|
);
|
|
|
|
goto ProviderInstall_return;
|
|
}
|
|
|
|
if (!((FARPROC) pfnGetProviderList = GetProcAddress(
|
|
hTapi32,
|
|
#ifdef UNICODE
|
|
(LPCSTR) "lineGetProviderListW"
|
|
#else // UNICODE
|
|
(LPCSTR) "lineGetProviderList"
|
|
#endif // UNICODE
|
|
)))
|
|
{
|
|
DPRINTF1(
|
|
"GetProcAddr(lineGetProviderList) failed, err=%d",
|
|
GetLastError()
|
|
);
|
|
|
|
goto ProviderInstall_unloadTapi32;
|
|
}
|
|
|
|
|
|
//
|
|
// Loop until we get the full provider list
|
|
//
|
|
|
|
dwTotalSize = sizeof (LINEPROVIDERLIST);
|
|
|
|
goto ProviderInstall_allocProviderList;
|
|
|
|
ProviderInstall_getProviderList:
|
|
|
|
if ((*pfnGetProviderList)(0x00020000, pProviderList) != 0)
|
|
{
|
|
goto ProviderInstall_freeProviderList;
|
|
}
|
|
|
|
if (pProviderList->dwNeededSize > pProviderList->dwTotalSize)
|
|
{
|
|
dwTotalSize = pProviderList->dwNeededSize;
|
|
|
|
LocalFree (pProviderList);
|
|
|
|
ProviderInstall_allocProviderList:
|
|
|
|
if (!(pProviderList = LocalAlloc (LPTR, dwTotalSize)))
|
|
{
|
|
lResult = LINEERR_NOMEM;
|
|
goto ProviderInstall_unloadTapi32;
|
|
}
|
|
|
|
pProviderList->dwTotalSize = dwTotalSize;
|
|
|
|
goto ProviderInstall_getProviderList;
|
|
}
|
|
|
|
|
|
//
|
|
// Inspect the provider list entries to see if this provider
|
|
// is already installed
|
|
//
|
|
|
|
pProviderEntry = (LPLINEPROVIDERENTRY) (((LPBYTE) pProviderList) +
|
|
pProviderList->dwProviderListOffset);
|
|
|
|
for (i = 0; i < pProviderList->dwNumProviders; i++)
|
|
{
|
|
LPTSTR pszInstalledProviderName =
|
|
(LPTSTR) ((LPBYTE) pProviderList
|
|
+ pProviderEntry->dwProviderFilenameOffset);
|
|
LPTSTR psz;
|
|
|
|
|
|
#ifdef DONT_WANT_C_RUNTIME
|
|
if ((psz = strrchr (pszInstalledProviderName, '\\')))
|
|
{
|
|
pszInstalledProviderName = psz + 1;
|
|
}
|
|
#else // DONT_WANT_C_RUNTIME
|
|
// The above code was trying to handle the case where a directory
|
|
// path gets returned. We need to do this in a way that doesn't
|
|
// load the C runtime code. Ie. search for the last '\\'.
|
|
{
|
|
LPTSTR pchLastWack;
|
|
|
|
pchLastWack = NULL;
|
|
psz = pszInstalledProviderName;
|
|
|
|
// Find the last '\\'.
|
|
while (*psz)
|
|
{
|
|
if (*psz == TEXT('\\'))
|
|
{
|
|
pchLastWack = psz;
|
|
}
|
|
psz++;
|
|
}
|
|
|
|
if (pchLastWack)
|
|
{
|
|
pszInstalledProviderName = pchLastWack + 1;
|
|
}
|
|
}
|
|
#endif // DONT_WANT_C_RUNTIME
|
|
|
|
if (lstrcmpi (pszInstalledProviderName, pszProviderName) == 0)
|
|
{
|
|
lResult = LINEERR_NOMULTIPLEINSTANCE;
|
|
goto ProviderInstall_freeProviderList;
|
|
}
|
|
|
|
pProviderEntry++;
|
|
}
|
|
|
|
|
|
//
|
|
// If here then the provider isn't currently installed,
|
|
// so do whatever configuration stuff is necessary and
|
|
// indicate SUCCESS
|
|
//
|
|
|
|
lResult = 0;
|
|
|
|
|
|
ProviderInstall_freeProviderList:
|
|
|
|
LocalFree (pProviderList);
|
|
|
|
ProviderInstall_unloadTapi32:
|
|
|
|
FreeLibrary (hTapi32);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do whatever configuration stuff is necessary and return SUCCESS
|
|
//
|
|
|
|
lResult = 0;
|
|
}
|
|
|
|
|
|
|
|
ProviderInstall_return:
|
|
|
|
return lResult;
|
|
}
|
|
|
|
|
|
|
|
#ifdef UNDER_CONSTRUCT
|
|
|
|
TCHAR gszModem[]="Modem";
|
|
|
|
LONG WINAPI
|
|
AddModemDependency(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
schSCManager=OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS
|
|
);
|
|
|
|
if (schSCManager != NULL) {
|
|
//
|
|
// now on service
|
|
//
|
|
schModemSys=OpenService(
|
|
schSCManager,
|
|
TEXT("tapisrv"),
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
|
|
if (schModemSys != NULL) {
|
|
|
|
|
|
ServiceConfig=LocalAlloc(lptr, 4096);
|
|
|
|
if (ServiceConfig == NULL) {
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
lResult=QueryServiceConfig(
|
|
schModemSys,
|
|
ServiceConfig,
|
|
4096,
|
|
&BytesNeeded
|
|
);
|
|
|
|
if (ERROR_SUCCESS != lResult) {
|
|
|
|
got Fail;
|
|
}
|
|
|
|
Length=RemoveModemSys(
|
|
ServiceConfig.lpDependencies
|
|
);
|
|
|
|
|
|
NewDependList=LocalAlloc(LPTR,Length+sizeof(gszModem)+2);
|
|
|
|
if (NewDependList == NULL) {
|
|
|
|
goto Fail;;
|
|
}
|
|
|
|
|
|
AddModemToDepend(
|
|
ServiceConfig.lpDependencies,
|
|
NewDependList
|
|
);
|
|
|
|
ServiceConfig.lpDependencies=NewDependList;
|
|
|
|
lResult=ChangeServiceConfig(
|
|
schModemSys,
|
|
ServiceConfig.dwServiceType,
|
|
ServiceConfig.dwStartType,
|
|
ServiceConfig.dwErrorControl,
|
|
ServiceConfig.lpBinaryPathName,
|
|
&TagValue,
|
|
ServiceConfig.dwTagId,
|
|
NewDependList,
|
|
ServiceConfig.lpServiceStartName,
|
|
NULL,
|
|
ServiceConfig.lpDisplayName
|
|
);
|
|
|
|
|
|
|
|
|
|
//****************************************************************************
|
|
// LONG TSPIAPI TSPI_providerCreateLineDevice()
|
|
//
|
|
// Dynamically creates a new device.
|
|
//
|
|
//****************************************************************************
|
|
|
|
LONG TSPIAPI TSPI_providerCreateLineDevice(DWORD dwTempID,
|
|
DWORD dwDeviceID)
|
|
{
|
|
|
|
LONG lResult = LINEERR_OPERATIONFAILED; // assume failure
|
|
DBG_DDI_ENTER("TSPI_providerCreateLineDevice");
|
|
|
|
|
|
TRACE3(
|
|
IDEVENT_TSPFN_ENTER,
|
|
IDFROM_TSPI_providerCreateLineDevice,
|
|
&dwTempID
|
|
);
|
|
|
|
// Let the device level handle it
|
|
//
|
|
lResult = DevlineNewDevice(dwTempID, dwDeviceID);
|
|
|
|
TRACE4(
|
|
IDEVENT_TSPFN_EXIT,
|
|
IDFROM_TSPI_providerCreateLineDevice,
|
|
&dwTempID,
|
|
lResult
|
|
);
|
|
|
|
DBG_DDI_EXIT("TSPI_providerCreateLineDevice", lResult);
|
|
return lResult;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// IsDeviceInService()
|
|
//
|
|
// Function: Finds the specified modem in the current modem list
|
|
//
|
|
//****************************************************************************
|
|
|
|
BOOL NEAR PASCAL IsDeviceInService(LPSTR szID)
|
|
{
|
|
DEVNODE dn;
|
|
DWORD dwStatus, dwProblem;
|
|
BOOL fRet = FALSE;
|
|
|
|
// Locate the devnode
|
|
//
|
|
if (CM_Locate_DevNode(&dn, szID, 0) == ERROR_SUCCESS)
|
|
{
|
|
// The devnode exists, check the devnode status
|
|
//
|
|
if (CM_Get_DevNode_Status(&dwStatus, &dwProblem, dn, 0) == ERROR_SUCCESS)
|
|
{
|
|
// If the device is in service only when it has no problem
|
|
//
|
|
fRet = ((dwStatus & DN_STARTED) != 0);
|
|
};
|
|
};
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// FindModemHWKey()
|
|
//
|
|
// Function: Finds the specified modem's hardware registry key
|
|
//
|
|
//****************************************************************************
|
|
|
|
DWORD NEAR PASCAL FindModemHWKey (LPSTR pszDeviceName, HKEY FAR* lphkey,
|
|
LPSTR pszID, UINT cbID)
|
|
{
|
|
FINDINFO fi;
|
|
|
|
// Package the enumeration data
|
|
//
|
|
fi.lpszDeviceName = (LPSTR)pszDeviceName;
|
|
fi.fFound = FALSE;
|
|
fi.lphkey = lphkey;
|
|
fi.lpszID = (LPSTR)pszID;
|
|
fi.cbID = cbID;
|
|
|
|
// Find the modem
|
|
//
|
|
return ((EnumerateModemKeys(SearchModemCallback, (LPVOID)&fi) == ERROR_SUCCESS) &&
|
|
(fi.fFound)) ? ERROR_SUCCESS : ERROR_BAD_DEVICE;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// lineNewDevice()
|
|
//
|
|
// Function: Emulate the TAPI lineInitialize call.
|
|
//
|
|
//****************************************************************************
|
|
|
|
LONG NEAR PASCAL DevlineNewDevice (DWORD dwTempID,
|
|
DWORD dwPermID)
|
|
{
|
|
HLOCAL hDeviceName;
|
|
PSTR pDeviceName;
|
|
HKEY hkeyModem;
|
|
DWORD dwRet;
|
|
char szID[MAXDEVICENAME+1];
|
|
|
|
// Get the name of the device
|
|
//
|
|
hDeviceName = (HLOCAL)LOWORD(dwTempID);
|
|
if ((pDeviceName = (PSTR)LocalLock(hDeviceName)) == NULL)
|
|
return LINEERR_BADDEVICEID;
|
|
|
|
// Assume failure
|
|
//
|
|
dwRet = LINEERR_OPERATIONFAILED;
|
|
|
|
// if we found the device, create the LINEDEV struct for it
|
|
//
|
|
if (FindModemHWKey(pDeviceName, &hkeyModem, szID, sizeof(szID))
|
|
== ERROR_SUCCESS)
|
|
{
|
|
PLINEDEV pLineDev;
|
|
|
|
if ((pLineDev = CreateLineDev(hkeyModem, dwPermID, szID)) != NULL)
|
|
{
|
|
// Insert into the LINEDEV list
|
|
//
|
|
pLineDev->pNext = gMdmDev;
|
|
gMdmDev = pLineDev;
|
|
dwRet = SUCCESS;
|
|
};
|
|
|
|
RegCloseKey(hkeyModem);
|
|
};
|
|
|
|
LocalUnlock(hDeviceName);
|
|
LocalFree(hDeviceName);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// lineDisabled()
|
|
//
|
|
// Function: Remove the LineDev structure.
|
|
//
|
|
//****************************************************************************
|
|
|
|
LONG NEAR PASCAL DevlineDisabled (PLINEDEV pLineDev)
|
|
{
|
|
PLINEDEV pCur, pPrevious;
|
|
|
|
// Notify TAPI for device out of service
|
|
//
|
|
if (pLineDev->lpfnEvent != NULL)
|
|
{
|
|
(*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_LINEDEVSTATE,
|
|
(pLineDev->fdwResources & LINEDEVFLAGS_REMOVING ?
|
|
LINEDEVSTATE_REMOVED : LINEDEVSTATE_OUTOFSERVICE),
|
|
0L, 0L);
|
|
(*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_CLOSE,
|
|
0L, 0L, 0L);
|
|
};
|
|
|
|
// If removal, free the resources for this modem
|
|
//
|
|
if (pLineDev->fdwResources & LINEDEVFLAGS_REMOVING)
|
|
{
|
|
// Walk the modem list
|
|
//
|
|
pPrevious = NULL;
|
|
pCur = gMdmDev;
|
|
while (pCur)
|
|
{
|
|
if (pCur == pLineDev)
|
|
break;
|
|
|
|
pPrevious = pCur;
|
|
pCur = pCur->pNext;
|
|
};
|
|
|
|
// Remove it from the list
|
|
//
|
|
if (pPrevious != NULL)
|
|
pPrevious->pNext = pLineDev->pNext;
|
|
else
|
|
gMdmDev = pLineDev->pNext;
|
|
|
|
// Free linedev's resources
|
|
//
|
|
CleanupLineDev(pLineDev);
|
|
|
|
if (pLineDev->pDevCfg != NULL)
|
|
LocalFree((HLOCAL)pLineDev->pDevCfg);
|
|
|
|
// Deallocate the port
|
|
//
|
|
LocalFree((HLOCAL)pLineDev);
|
|
};
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// MdmDeviceChangeNotify()
|
|
//
|
|
// Function: Notify a change in modem list.
|
|
//
|
|
// Returns: SUCCESS
|
|
//
|
|
//****************************************************************************
|
|
|
|
DWORD NEAR PASCAL MdmDeviceChangeNotify (UINT uEvent, LPSTR szDevice)
|
|
{
|
|
HLOCAL hDeviceName;
|
|
PSTR pDeviceName;
|
|
|
|
// Allocate a local buffer for the device name
|
|
//
|
|
if ((hDeviceName = LocalAlloc(LMEM_MOVEABLE,
|
|
sizeof(TCHAR) * (MAXDEVICENAME+1))) != NULL)
|
|
{
|
|
if ((pDeviceName = (PSTR)LocalLock(hDeviceName)) != NULL)
|
|
{
|
|
// Remember the new device name
|
|
//
|
|
lstrcpyn((LPSTR)pDeviceName, szDevice, MAXDEVICENAME+1);
|
|
LocalUnlock(hDeviceName);
|
|
|
|
// Signal ourselves to start adding at a better time
|
|
//
|
|
PostMessage(ghwndMdm, WM_MDMCHANGE, (WPARAM)uEvent,
|
|
(LPARAM)MAKELONG(hDeviceName, 0));
|
|
}
|
|
else
|
|
{
|
|
LocalFree(hDeviceName);
|
|
};
|
|
};
|
|
return SUCCESS;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// MdmDeviceChanged()
|
|
//
|
|
// Function: Handle a device change notification.
|
|
//
|
|
// Returns: SUCCESS
|
|
//
|
|
//****************************************************************************
|
|
|
|
DWORD NEAR PASCAL MdmDeviceChanged (UINT uEvent, LPARAM lParam)
|
|
{
|
|
HLOCAL hDeviceName;
|
|
PSTR pDeviceName;
|
|
PLINEDEV pLineDev;
|
|
|
|
// Get the name of the modem that is changed
|
|
//
|
|
hDeviceName = (HLOCAL)LOWORD(lParam);
|
|
if ((pDeviceName = (PSTR)LocalLock(hDeviceName)) == NULL)
|
|
{
|
|
// Excuse me! something is terribly wrong here.
|
|
//
|
|
ASSERT(0);
|
|
return ERROR_INVALID_HANDLE;
|
|
};
|
|
|
|
// Search for an existing device
|
|
//
|
|
pLineDev = GetCBfromName(pDeviceName);
|
|
LocalUnlock(hDeviceName);
|
|
|
|
// Determine the type of change
|
|
//
|
|
switch (uEvent)
|
|
{
|
|
//************************************************************************
|
|
// Notify TAPI of the new device
|
|
//************************************************************************
|
|
|
|
case UMDM_ADD:
|
|
{
|
|
// If not found, it is a new device
|
|
//
|
|
if (pLineDev == NULL)
|
|
{
|
|
(*gfnLineCreateProc)(NULL, NULL, LINE_CREATE, (DWORD)ghProvider,
|
|
(DWORD)lParam, 0L);
|
|
|
|
// Return here so that the device name token is not freed.
|
|
//
|
|
return ERROR_SUCCESS;
|
|
};
|
|
break;
|
|
}
|
|
|
|
//************************************************************************
|
|
// Enable modem device, i.e. the modem devnode becomes enabled
|
|
//************************************************************************
|
|
|
|
case UMDM_ENABLE:
|
|
|
|
// If the device exists and is out of service, make it in service.
|
|
//
|
|
if (pLineDev != NULL)
|
|
{
|
|
if (pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE)
|
|
{
|
|
pLineDev->fdwResources &= ~LINEDEVFLAGS_OUTOFSERVICE;
|
|
if (pLineDev->lpfnEvent != NULL)
|
|
{
|
|
(*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_LINEDEVSTATE,
|
|
LINEDEVSTATE_INSERVICE, 0L, 0L);
|
|
};
|
|
};
|
|
};
|
|
break;
|
|
|
|
//************************************************************************
|
|
// Disable modem device, i.e. the modem devnode becomes disabled, and
|
|
// probably remove the modem from the list
|
|
//************************************************************************
|
|
|
|
case UMDM_DISABLE:
|
|
|
|
// If we found the disabled device
|
|
//
|
|
if ((pLineDev != NULL) &&
|
|
(pLineDev->fdwResources & LINEDEVFLAGS_OUTOFSERVICE))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//************************************************************************
|
|
// Fall through
|
|
//************************************************************************
|
|
|
|
case UMDM_REMOVE:
|
|
|
|
// If we found the disabled device
|
|
//
|
|
if (pLineDev != NULL)
|
|
{
|
|
pLineDev->fdwResources |= LINEDEVFLAGS_OUTOFSERVICE;
|
|
if (uEvent == UMDM_REMOVE)
|
|
{
|
|
pLineDev->fdwResources |= LINEDEVFLAGS_REMOVING;
|
|
};
|
|
|
|
// Is the modem active?
|
|
//
|
|
if ((pLineDev->dwCall & CALL_ALLOCATED) &&
|
|
(pLineDev->dwCallState != LINECALLSTATE_DISCONNECTED))
|
|
{
|
|
// We need to clean up the active connection first
|
|
//
|
|
MdmCompleteAsync (pLineDev, MDM_HANGUP, MDM_ID_NULL);
|
|
}
|
|
else
|
|
{
|
|
// The modem might be listening, just close the modem
|
|
//
|
|
if ((pLineDev->DevState == DEVST_PORTLISTENINIT) ||
|
|
(pLineDev->DevState == DEVST_PORTLISTENING))
|
|
{
|
|
// Notify the monitoring application
|
|
//
|
|
(*pLineDev->lpfnEvent)(pLineDev->htLine, NULL, LINE_CLOSE,
|
|
0L, 0L, 0L);
|
|
DevlineClose(pLineDev);
|
|
};
|
|
|
|
// disable or remove it immediately
|
|
//
|
|
DevlineDisabled(pLineDev);
|
|
};
|
|
};
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
};
|
|
|
|
// We no longer need the device name token
|
|
//
|
|
LocalFree(hDeviceName);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
#endif //UNDER_CONSTRUCT
|
|
|
|
|
|
#ifndef DYNA_ADDREMOVE
|
|
|
|
LONG TSPIAPI TSPI_providerCreateLineDevice(DWORD dwTempID,
|
|
DWORD dwDeviceID)
|
|
{
|
|
ASSERT(FALSE);
|
|
return LINEERR_OPERATIONFAILED;
|
|
}
|
|
|
|
#else // DYNA_ADDREMOVE
|
|
|
|
BOOL ReInitModemCallback (HKEY hkey, LPVOID lpData);
|
|
LONG DevlineNewDevice (DWORD dwTempID, DWORD dwPermID);
|
|
|
|
|
|
//****************************************************************************
|
|
// LONG DevlineReInitialize()
|
|
//
|
|
// Function: Re-initializes the modem device list
|
|
//
|
|
// History:
|
|
// 4/15/96 JosephJ Created
|
|
//****************************************************************************
|
|
|
|
LONG DevlineReInitialize (DWORD dwBaseID,
|
|
LPDWORD lpdwNumDevs)
|
|
{
|
|
INITINFO initi;
|
|
DWORD dwRet = LINEERR_OPERATIONFAILED;
|
|
BOOL fModemUILoaded;
|
|
HDEVINFO hdevinfo=NULL;
|
|
|
|
// Load MODEMUI.DLL (for private entry points)
|
|
fModemUILoaded=TRUE;
|
|
if (!LoadModemUI())
|
|
{
|
|
fModemUILoaded=FALSE;
|
|
goto end;
|
|
}
|
|
|
|
// For the modem device, get the device information
|
|
hdevinfo = GetHDevInfo(DIGCF_PRESENT);
|
|
if (!hdevinfo)
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
initi.dwBaseID = dwBaseID;
|
|
initi.cModem = 0;
|
|
|
|
// We do this enumeration inside the global critical section, because there
|
|
// Potentially could be more than one tepCplNotif threads active.
|
|
// It's almost impossible to do this manually -- one would have to add/remove
|
|
// modems real fast in succession so that the 2nd notification comes in when
|
|
// the 1st is still proceeding, but it's possible, and we definitely want to
|
|
// serialize the marking of all the modems with the REINIT flag and
|
|
// subsequently declaring all the unmarked ones out-of-service. Also there
|
|
// is the possibility of both threads deciding that a modem needs to be
|
|
// created and creating two instances of them.
|
|
EnterCriticalSection(&gUmdm.crit);
|
|
dwRet = EnumerateModems(ReInitModemCallback, (LPVOID)&initi, TRUE);
|
|
if (dwRet == ERROR_SUCCESS)
|
|
{
|
|
DisableStaleModems();
|
|
*lpdwNumDevs = initi.cModem;
|
|
}
|
|
else
|
|
*lpdwNumDevs = 0;
|
|
LeaveCriticalSection(&gUmdm.crit);
|
|
|
|
end:
|
|
|
|
if (fModemUILoaded)
|
|
{
|
|
UnloadModemUI();
|
|
}
|
|
if (hdevinfo)
|
|
{
|
|
FreeHDevInfo(hdevinfo);
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// BOOL ReInitModemCallback (HKEY hkey, LPVOID lpData)
|
|
//
|
|
// Function: ReInitializes the enumerated modems.
|
|
//
|
|
// Returns: TRUE always to continue
|
|
//
|
|
//****************************************************************************
|
|
|
|
BOOL ReInitModemCallback (HKEY hkey, LPVOID lpData)
|
|
{
|
|
PLINEDEV pMdmDev;
|
|
LPINITINFO lpInitInfo = (LPINITINFO)lpData;
|
|
|
|
pMdmDev = CreateLineDev(hkey, MAXDWORD, TRUE);
|
|
if (pMdmDev)
|
|
{
|
|
// Insert into the LINEDEV list
|
|
//
|
|
AddCBToList(pMdmDev);
|
|
(lpInitInfo->cModem)++;
|
|
|
|
// Let's callback the LINE_CREATE function here, passing in pMdmDev
|
|
// as the handle.
|
|
// Note: we haven't claimed any crit-sections at this time.
|
|
if (gfnLineCreateProc)
|
|
{
|
|
(*gfnLineCreateProc)(NULL, NULL, LINE_CREATE, (DWORD)ghProvider,
|
|
(DWORD)pMdmDev, 0L);
|
|
}
|
|
};
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// LONG TSPIAPI TSPI_providerCreateLineDevice()
|
|
//
|
|
// Dynamically creates a new device.
|
|
//
|
|
//****************************************************************************
|
|
|
|
LONG TSPIAPI TSPI_providerCreateLineDevice(DWORD dwTempID,
|
|
DWORD dwDeviceID)
|
|
{
|
|
LONG lResult;
|
|
|
|
DBG_DDI_ENTER("TSPI_providerCreateLineDevice");
|
|
TRACE3(IDEVENT_TSPFN_ENTER, IDFROM_TSPI_providerCreateLineDevice, &dwTempID);
|
|
|
|
// Let the device level handle it
|
|
//
|
|
lResult = DevlineNewDevice(dwTempID, dwDeviceID);
|
|
|
|
TRACE4(
|
|
IDEVENT_TSPFN_EXIT,
|
|
IDFROM_TSPI_providerCreateLineDevice,
|
|
&dwTempID,
|
|
lResult
|
|
);
|
|
DBG_DDI_EXIT("TSPI_providerCreateLineDevice", lResult);
|
|
return lResult;
|
|
}
|
|
|
|
|
|
|
|
//****************************************************************************
|
|
// lineNewDevice()
|
|
//
|
|
// Function: Emulate the TAPI lineInitialize call.
|
|
//
|
|
//****************************************************************************
|
|
|
|
LONG DevlineNewDevice (DWORD dwTempID,
|
|
DWORD dwPermID)
|
|
{
|
|
LPSTR lpDeviceName;
|
|
HKEY hkeyModem;
|
|
DWORD dwRet;
|
|
char szID[MAXDEVICENAME+1];
|
|
PLINEDEV pLineDev;
|
|
|
|
DPRINTF2("DevlineNewDevice(%lu,%lu)", dwTempID, dwPermID);
|
|
|
|
// Retrieve the device
|
|
//
|
|
pLineDev = GetCBfromHandle (dwTempID);
|
|
if (!pLineDev)
|
|
{
|
|
dwRet=LINEERR_BADDEVICEID;
|
|
goto end;
|
|
}
|
|
|
|
// Assume failure
|
|
//
|
|
dwRet = LINEERR_OPERATIONFAILED;
|
|
|
|
// if we found the device, we finish initializing it -- specify
|
|
// the proper dwPermID, etc...
|
|
//
|
|
ASSERT(pLineDev->dwID == MAXDWORD);
|
|
pLineDev->dwID=dwPermID;
|
|
RELEASE_LINEDEV(pLineDev);
|
|
dwRet = ERROR_SUCCESS;
|
|
|
|
end:
|
|
return dwRet;
|
|
}
|
|
#endif // DYNA_ADDREMOVE
|
|
|
|
//
|
|
// Thread Entry Point for the thread that processes cpl notifications.
|
|
//
|
|
DWORD APIENTRY tepCplNotif(DWORD dwParam)
|
|
{
|
|
DWORD dwcbNew;
|
|
PNOTIFICATION_FRAME pnf = (PNOTIFICATION_FRAME) dwParam;
|
|
|
|
ASSERT(pnf && TSP_CPL_FRAME(pnf));
|
|
|
|
if (pnf->dwFlags&fTSPNOTIF_FLAG_CPL_REENUM)
|
|
{
|
|
DevlineReInitialize (0, &dwcbNew);
|
|
}
|
|
else if (pnf->dwFlags&fTSPNOTIF_FLAG_CPL_DEFAULT_COMMCONFIG_CHANGE)
|
|
{
|
|
if (!(pnf->dwFlags&fTSPNOTIF_FLAG_UNICODE))
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
else
|
|
{
|
|
// Get friendly name and refresh comm config.
|
|
LPCTSTR lpctszFriendlyName = (LPCTSTR) pnf->rgb;
|
|
UINT uMaxSize = pnf->dwSize - sizeof(NOTIFICATION_FRAME);
|
|
UINT u;
|
|
|
|
ASSERT(pnf->dwSize > sizeof(NOTIFICATION_FRAME));
|
|
|
|
// verify string is null-terminated.
|
|
for(u=0;u<uMaxSize;u++)
|
|
{
|
|
if (!lpctszFriendlyName[u]) break;
|
|
}
|
|
|
|
ASSERT(u<uMaxSize);
|
|
|
|
if (u<uMaxSize)
|
|
{
|
|
PLINEDEV pLineDev = GetCBfromName (
|
|
(LPTSTR) lpctszFriendlyName
|
|
);
|
|
|
|
if (pLineDev)
|
|
{
|
|
DPRINTF1(
|
|
"CPLNOTIF: Marking device [%s] for refresh",
|
|
lpctszFriendlyName
|
|
);
|
|
pLineDev->fUpdateDefaultCommConfig=TRUE;
|
|
RELEASE_LINEDEV(pLineDev); pLineDev=NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Our job to free this.
|
|
LocalFree(pnf);
|
|
|
|
CplNotifComplete(FALSE);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
void cplProcessNotification(PNOTIFICATION_FRAME pnf)
|
|
{
|
|
|
|
ASSERT(TSP_CPL_FRAME(pnf));
|
|
{
|
|
HANDLE hThread;
|
|
DWORD dwTID;
|
|
DPRINTF("Processing CPL Notification");
|
|
|
|
#ifdef DYNA_ADDREMOVE
|
|
EnterCriticalSection(&gUmdm.critCplNotif);
|
|
if (gUmdm.hthrdCplNotif)
|
|
{
|
|
DPRINTF("cplProcessNotification: Previous CplNotif thread exists. Skipping.");
|
|
}
|
|
else
|
|
{
|
|
PNOTIFICATION_FRAME pnfAlloc =
|
|
(PNOTIFICATION_FRAME) LocalAlloc
|
|
(
|
|
LPTR,
|
|
pnf->dwSize
|
|
);
|
|
if (pnfAlloc)
|
|
{
|
|
|
|
CopyMemory(pnfAlloc, pnf, pnf->dwSize);
|
|
|
|
// Start the thread to process the notification
|
|
//
|
|
gUmdm.hthrdCplNotif = CreateThread(
|
|
NULL, // default security
|
|
0, // default stack size
|
|
(LPTHREAD_START_ROUTINE)tepCplNotif, // thread entry point
|
|
pnfAlloc, // parameter
|
|
0, // Start immediately
|
|
&dwTID); // thread id
|
|
|
|
if (gUmdm.hthrdCplNotif)
|
|
{
|
|
|
|
DPRINTF2("cplNotification: Created Thread @%lu; TID=0x%lx\n",
|
|
GetTickCount(),
|
|
dwTID);
|
|
}
|
|
else
|
|
{
|
|
DPRINTF1("cplNotification: Created Thread FAILED. Err=%lu\n",
|
|
GetLastError());
|
|
LocalFree(pnfAlloc);
|
|
pnfAlloc=NULL;
|
|
}
|
|
}
|
|
}
|
|
LeaveCriticalSection(&gUmdm.critCplNotif);
|
|
#endif // DYNA_ADDREMOVE
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef DYNA_ADDREMOVE
|
|
HDEVINFO GetHDevInfo(DWORD dwDIGCF)
|
|
{
|
|
HDEVINFO hdevinfo=NULL;
|
|
|
|
EnterCriticalSection(&gUmdm.crit);
|
|
|
|
if (!gUmdm.dwcRefHDevInfo)
|
|
{
|
|
gUmdm.hdevinfo = SetupDiGetClassDevsW(
|
|
g_pguidModem,
|
|
NULL,
|
|
NULL,
|
|
dwDIGCF);
|
|
}
|
|
|
|
hdevinfo=gUmdm.hdevinfo;
|
|
|
|
if (hdevinfo)
|
|
{
|
|
gUmdm.dwcRefHDevInfo++;
|
|
}
|
|
|
|
ASSERT( ( hdevinfo && gUmdm.dwcRefHDevInfo)
|
|
||(!hdevinfo && !gUmdm.dwcRefHDevInfo) );
|
|
|
|
LeaveCriticalSection(&gUmdm.crit);
|
|
|
|
return hdevinfo;
|
|
}
|
|
#endif // DYNA_ADDREMOVE
|
|
|
|
|
|
|
|
#ifdef DYNA_ADDREMOVE
|
|
void FreeHDevInfo(HDEVINFO hdevinfo)
|
|
{
|
|
|
|
EnterCriticalSection(&gUmdm.crit);
|
|
|
|
ASSERT(hdevinfo==gUmdm.hdevinfo);
|
|
|
|
if (!gUmdm.dwcRefHDevInfo)
|
|
{
|
|
ASSERT(FALSE);
|
|
goto end;
|
|
}
|
|
if (!--gUmdm.dwcRefHDevInfo)
|
|
{
|
|
SetupDiDestroyDeviceInfoList(gUmdm.hdevinfo);
|
|
gUmdm.hdevinfo=NULL;
|
|
}
|
|
|
|
end:
|
|
|
|
LeaveCriticalSection(&gUmdm.crit);
|
|
|
|
}
|
|
#endif // DYNA_ADDREMOVE
|
|
|
|
|
|
#ifdef DYNA_ADDREMOVE
|
|
BOOL LoadModemUI(void)
|
|
{
|
|
BOOL fRet=FALSE;
|
|
|
|
EnterCriticalSection(&gUmdm.crit);
|
|
|
|
if (!gUmdm.dwcRefModemUI)
|
|
{
|
|
HINSTANCE hlib = LoadLibrary(TEXT("modemui.dll"));
|
|
|
|
ASSERT(!gUmdm.hModemUIDLL);
|
|
ASSERT(!gUmdm.pfnPrivateDefCommConfig);
|
|
|
|
if (hlib)
|
|
{
|
|
|
|
gUmdm.pfnPrivateDefCommConfig=
|
|
(PVOID)GetProcAddress(hlib,"UnimodemGetDefaultCommConfig");
|
|
|
|
if (!gUmdm.pfnPrivateDefCommConfig)
|
|
{
|
|
FreeLibrary(hlib);
|
|
hlib=NULL;
|
|
}
|
|
}
|
|
|
|
gUmdm.hModemUIDLL = hlib;
|
|
}
|
|
|
|
if (gUmdm.hModemUIDLL)
|
|
{
|
|
gUmdm.dwcRefModemUI++;
|
|
fRet=TRUE;
|
|
}
|
|
|
|
ASSERT( ( gUmdm.hModemUIDLL && gUmdm.dwcRefModemUI)
|
|
||(!gUmdm.hModemUIDLL && !gUmdm.dwcRefModemUI) );
|
|
|
|
LeaveCriticalSection(&gUmdm.crit);
|
|
|
|
return fRet;
|
|
}
|
|
#endif // DYNA_ADDREMOVE
|
|
|
|
|
|
#ifdef DYNA_ADDREMOVE
|
|
void UnloadModemUI(void)
|
|
{
|
|
|
|
EnterCriticalSection(&gUmdm.crit);
|
|
|
|
if (!gUmdm.dwcRefModemUI)
|
|
{
|
|
ASSERT(FALSE);
|
|
goto end;
|
|
}
|
|
|
|
if (!--gUmdm.dwcRefModemUI)
|
|
{
|
|
ASSERT(gUmdm.hModemUIDLL && gUmdm.pfnPrivateDefCommConfig);
|
|
FreeLibrary(gUmdm.hModemUIDLL);
|
|
gUmdm.hModemUIDLL=NULL;
|
|
gUmdm.pfnPrivateDefCommConfig=NULL;
|
|
}
|
|
|
|
end:
|
|
|
|
LeaveCriticalSection(&gUmdm.crit);
|
|
|
|
}
|
|
#endif // DYNA_ADDREMOVE
|
|
|
|
|
|
#ifdef DYNA_ADDREMOVE
|
|
void CplNotifComplete(BOOL fWait)
|
|
{
|
|
HANDLE hthrd;
|
|
|
|
EnterCriticalSection(&gUmdm.critCplNotif);
|
|
hthrd=gUmdm.hthrdCplNotif;
|
|
gUmdm.hthrdCplNotif=0;
|
|
LeaveCriticalSection(&gUmdm.critCplNotif);
|
|
|
|
if (hthrd)
|
|
{
|
|
if (fWait)
|
|
{
|
|
DPRINTF("CplNotifComplete: WARNING -- waiting for re-enum thread to complete");
|
|
WaitForSingleObject(hthrd, INFINITE);
|
|
}
|
|
CloseHandle(hthrd);
|
|
}
|
|
}
|
|
#endif // DYNA_ADDREMOVE
|
|
|
|
//
|
|
// Reset the cached CommConfig structure by calling GetDefaultCommConfig.
|
|
//
|
|
void RefreshDefaultCommConfig(PLINEDEV pLineDev)
|
|
{
|
|
|
|
COMMCONFIG * pccCurrent = NULL, * pccNew = NULL;
|
|
LPCTSTR lpctszDeviceName = NULL;
|
|
|
|
if (pLineDev && pLineDev->pDevCfg)
|
|
{
|
|
pccCurrent = (COMMCONFIG *)&(pLineDev->pDevCfg->commconfig);
|
|
lpctszDeviceName = pLineDev->szDeviceName;
|
|
}
|
|
|
|
if (!pccCurrent || !lpctszDeviceName) goto end;
|
|
|
|
|
|
// Get default comm config.
|
|
{
|
|
DWORD dwSize = pccCurrent->dwSize;
|
|
|
|
DPRINTF1("RefreshDefaultCommConfig: [%s]", lpctszDeviceName);
|
|
|
|
pccNew = (COMMCONFIG *)LocalAlloc(LPTR, (UINT)dwSize);
|
|
if (pccNew)
|
|
{
|
|
pccNew->dwProviderSubType = PST_MODEM;
|
|
if (!GetDefaultCommConfig(lpctszDeviceName, pccNew, &dwSize))
|
|
{
|
|
DPRINTF2
|
|
(
|
|
"RefreshCommComfig: GetDefaultCommConfig(\"%s\"): ERR %08lu",
|
|
lpctszDeviceName,
|
|
GetLastError()
|
|
);
|
|
LocalFree(pccNew); pccNew = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pccNew)
|
|
{
|
|
// Similar to what is done by TSPI_lineSetDevConfig.
|
|
|
|
ASSERT(pccCurrent->dwSize == pccNew->dwSize);
|
|
ASSERT(pccCurrent->wVersion == pccNew->wVersion);
|
|
ASSERT(pccCurrent->dwProviderSubType == pccNew->dwProviderSubType);
|
|
ASSERT(pccCurrent->dwProviderSize == pccNew->dwProviderSize);
|
|
if
|
|
( (pccCurrent->dwSize == pccNew->dwSize)
|
|
&& (pccCurrent->wVersion == pccNew->wVersion)
|
|
&& (pccCurrent->dwProviderSubType == pccNew->dwProviderSubType)
|
|
&& (pccCurrent->dwProviderSize == pccNew->dwProviderSize)
|
|
)
|
|
{
|
|
|
|
pccCurrent->dcb = pccNew->dcb;
|
|
CopyMemory(((LPBYTE)pccCurrent)+pccCurrent->dwProviderOffset,
|
|
((LPBYTE)pccNew)+pccNew->dwProviderOffset,
|
|
pccCurrent->dwProviderSize);
|
|
|
|
pLineDev->InitStringsAreValid=FALSE;
|
|
}
|
|
else
|
|
{
|
|
DPRINTF("RefreshDefaultCommSettings:size/version/prov. mismatch");
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
end:
|
|
|
|
if (pccNew) {LocalFree(pccNew); pccNew = NULL;}
|
|
|
|
}
|
|
|
|
// Initialize the global parameters
|
|
//
|
|
void tspInitGlobals(void)
|
|
{
|
|
// Determine if User is Admin
|
|
gUmdm.bAdminUser = IsAdminUser();
|
|
|
|
// Determine global registry state flags.
|
|
{
|
|
TCHAR rgtch[] = szUNIMODEM_REG_PATH TEXT("\\PortSpecific");
|
|
HKEY hKey=NULL;
|
|
LONG l;
|
|
|
|
gRegistryFlags = 0;
|
|
|
|
l=RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE, // handle of open key
|
|
rgtch, // address of name of subkey to open
|
|
0, // reserved
|
|
KEY_READ, // desired security access
|
|
&hKey // address of buffer for opened handle
|
|
);
|
|
|
|
if (l==ERROR_SUCCESS)
|
|
{
|
|
gRegistryFlags = fGRF_PORTLATENCY;
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
// DeInitialize the global parameters
|
|
//
|
|
void tspDeInitGlobals(void)
|
|
{
|
|
gRegistryFlags = 0;
|
|
gUmdm.bAdminUser = FALSE;
|
|
}
|