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