Windows NT 4.0 source code leak
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

//****************************************************************************
//
// 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 *)&regdevcaps,
&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;
}