summaryrefslogtreecommitdiffstats
path: root/private/unimodem/tapisp/umdminit.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/unimodem/tapisp/umdminit.c')
-rw-r--r--private/unimodem/tapisp/umdminit.c2792
1 files changed, 2792 insertions, 0 deletions
diff --git a/private/unimodem/tapisp/umdminit.c b/private/unimodem/tapisp/umdminit.c
new file mode 100644
index 000000000..aa4ec1ad5
--- /dev/null
+++ b/private/unimodem/tapisp/umdminit.c
@@ -0,0 +1,2792 @@
+//****************************************************************************
+//
+// 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;
+}