mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1824 lines
50 KiB
1824 lines
50 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1993-1994
|
|
//
|
|
// File: modemui.c
|
|
//
|
|
// This files contains the DLL entry-points.
|
|
//
|
|
// Much of this file contains the code that builds the default property dialog
|
|
// for modem devices.
|
|
//
|
|
// This code was originally lifted from SETUP4.DLL, which performs essentially
|
|
// the same thing, except for any device. We don't want to have to link to
|
|
// SETUP4.DLL, so we contain a copy of this code.
|
|
//
|
|
//
|
|
// History:
|
|
// 1-12-94 ScottH Created
|
|
// 9-20-95 ScottH Ported to NT
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
#include "proj.h" // common headers
|
|
|
|
#define INITGUID
|
|
#include <initguid.h>
|
|
#include <devguid.h>
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
|
|
LPGUID c_pguidModem = (LPGUID)&GUID_DEVCLASS_MODEM;
|
|
|
|
#pragma data_seg()
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
// The Unimodem provider fills in the COMMCONFIG structure as
|
|
// follows:
|
|
//
|
|
// +-----------------------+
|
|
// | |
|
|
// | COMMCONFIG data |
|
|
// | |
|
|
// | Provider offset |--+
|
|
// | Provider size | |
|
|
// | = ms.size | |
|
|
// | | |
|
|
// +-----------------------+ |
|
|
// | |<-+
|
|
// | MODEMSETTINGS |
|
|
// | |
|
|
// | Size |
|
|
// | = MODEMSETTINGS + |
|
|
// | dev.size |
|
|
// | |
|
|
// | DevSpecific offset |--+
|
|
// | DevSpecific size | |
|
|
// | = DEVSPECIFIC | |
|
|
// +-----------------------+ |
|
|
// | |<-+
|
|
// | DEVSPECIFIC |
|
|
// | (optional) |
|
|
// | |
|
|
// +-----------------------+
|
|
//
|
|
|
|
|
|
#define CB_COMMCONFIG_HEADER FIELDOFFSET(COMMCONFIG, wcProviderData)
|
|
#define CB_PRIVATESIZE (CB_COMMCONFIG_HEADER)
|
|
#define CB_PROVIDERSIZE (sizeof(MODEMSETTINGS))
|
|
#define CB_COMMCONFIGSIZE (CB_PRIVATESIZE+CB_PROVIDERSIZE)
|
|
|
|
#define CB_MODEMSETTINGS_HEADER FIELDOFFSET(MODEMSETTINGS, dwCallSetupFailTimer)
|
|
#define CB_MODEMSETTINGS_TAIL (sizeof(MODEMSETTINGS) - FIELDOFFSET(MODEMSETTINGS, dwNegotiatedModemOptions))
|
|
#define CB_MODEMSETTINGS_OVERHEAD (CB_MODEMSETTINGS_HEADER + CB_MODEMSETTINGS_TAIL)
|
|
|
|
#define PmsFromPcc(pcc) ((LPMODEMSETTINGS)(pcc)->wcProviderData)
|
|
|
|
|
|
#define MAX_PROP_PAGES 16 // Define a reasonable limit
|
|
|
|
#define MIN_CALL_SETUP_FAIL_TIMER 1
|
|
#define MIN_INACTIVITY_TIMEOUT 0
|
|
#define DEFAULT_INACTIVITY_SCALE 10 // == decasecond units
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// Debug routines
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose:
|
|
Returns:
|
|
Cond: --
|
|
*/
|
|
void PRIVATE DumpModemSettings(
|
|
LPMODEMSETTINGS pms)
|
|
{
|
|
ASSERT(pms);
|
|
|
|
if (IsFlagSet(g_dwDumpFlags, DF_MODEMSETTINGS))
|
|
{
|
|
int i;
|
|
LPDWORD pdw = (LPDWORD)pms;
|
|
|
|
TRACE_MSG(TF_ALWAYS, "MODEMSETTINGS %08lx %08lx %08lx %08lx", pdw[0], pdw[1],
|
|
pdw[2], pdw[3]);
|
|
pdw += 4;
|
|
for (i = 0; i < sizeof(MODEMSETTINGS)/sizeof(DWORD); i += 4, pdw += 4)
|
|
{
|
|
TRACE_MSG(TF_ALWAYS, " %08lx %08lx %08lx %08lx", pdw[0], pdw[1],
|
|
pdw[2], pdw[3]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose:
|
|
Returns:
|
|
Cond: --
|
|
*/
|
|
void PRIVATE DumpDCB(
|
|
LPWIN32DCB pdcb)
|
|
{
|
|
ASSERT(pdcb);
|
|
|
|
if (IsFlagSet(g_dwDumpFlags, DF_DCB))
|
|
{
|
|
int i;
|
|
LPDWORD pdw = (LPDWORD)pdcb;
|
|
|
|
TRACE_MSG(TF_ALWAYS, "DCB %08lx %08lx %08lx %08lx", pdw[0], pdw[1], pdw[2], pdw[3]);
|
|
pdw += 4;
|
|
for (i = 0; i < sizeof(WIN32DCB)/sizeof(DWORD); i += 4, pdw += 4)
|
|
{
|
|
TRACE_MSG(TF_ALWAYS, " %08lx %08lx %08lx %08lx", pdw[0], pdw[1], pdw[2], pdw[3]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose:
|
|
Returns:
|
|
Cond: --
|
|
*/
|
|
void PRIVATE DumpDevCaps(
|
|
LPREGDEVCAPS pdevcaps)
|
|
{
|
|
ASSERT(pdevcaps);
|
|
|
|
if (IsFlagSet(g_dwDumpFlags, DF_DEVCAPS))
|
|
{
|
|
int i;
|
|
LPDWORD pdw = (LPDWORD)pdevcaps;
|
|
|
|
TRACE_MSG(TF_ALWAYS, "PROPERTIES %08lx %08lx %08lx %08lx", pdw[0], pdw[1], pdw[2], pdw[3]);
|
|
pdw += 4;
|
|
for (i = 0; i < sizeof(REGDEVCAPS)/sizeof(DWORD); i += 4, pdw += 4)
|
|
{
|
|
TRACE_MSG(TF_ALWAYS, " %08lx %08lx %08lx %08lx", pdw[0], pdw[1], pdw[2], pdw[3]);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif //DEBUG
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns value of the InactivityScale value in the registry.
|
|
|
|
Returns: see above
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE GetInactivityTimeoutScale(
|
|
HKEY hkey)
|
|
{
|
|
DWORD dwInactivityScale;
|
|
DWORD dwType;
|
|
DWORD cbData;
|
|
|
|
cbData = sizeof(DWORD);
|
|
if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szInactivityScale, NULL, &dwType,
|
|
(LPBYTE)&dwInactivityScale, &cbData) ||
|
|
REG_BINARY != dwType ||
|
|
sizeof(DWORD) != cbData ||
|
|
0 == dwInactivityScale)
|
|
{
|
|
dwInactivityScale = DEFAULT_INACTIVITY_SCALE;
|
|
}
|
|
return dwInactivityScale;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Gets a WIN32DCB from the registry.
|
|
|
|
Returns: One of the ERROR_ values
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE RegQueryDCB(
|
|
HKEY hkey,
|
|
WIN32DCB FAR * pdcb)
|
|
{
|
|
DWORD dwRet = ERROR_BADKEY;
|
|
DWORD cbData;
|
|
|
|
ASSERT(pdcb);
|
|
|
|
// Does the DCB key exist in the driver key?
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szDCB, NULL, NULL, NULL, &cbData))
|
|
{
|
|
// Yes; is the size in the registry okay?
|
|
if (sizeof(*pdcb) < cbData)
|
|
{
|
|
// No; the registry has bogus data
|
|
dwRet = ERROR_BADDB;
|
|
}
|
|
else
|
|
{
|
|
// Yes; get the DCB from the registry
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szDCB, NULL, NULL, (LPBYTE)pdcb, &cbData))
|
|
{
|
|
if (sizeof(*pdcb) == pdcb->DCBlength)
|
|
{
|
|
dwRet = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
dwRet = ERROR_BADDB;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRet = ERROR_BADKEY;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Gets a MODEMSETTINGS struct from the registry. Also
|
|
sets *pdwSize bigger if the data in the registry includes
|
|
extra data.
|
|
|
|
Returns: One of the ERROR_ values
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE RegQueryModemSettings(
|
|
HKEY hkey,
|
|
LPMODEMSETTINGS pms,
|
|
LPDWORD pdwSize) // Size of modem settings struct
|
|
{
|
|
DWORD dwRet;
|
|
DWORD cbData;
|
|
DWORD cbRequiredSize;
|
|
|
|
ASSERT(pms);
|
|
ASSERT(pdwSize);
|
|
|
|
// Is the MODEMSETTINGS ("Default") value in the driver key?
|
|
dwRet = RegQueryValueEx(hkey, c_szDefault, NULL, NULL, NULL, &cbData);
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
// Yes
|
|
|
|
// (Remember the Default value is a subset of the MODEMSETTINGS
|
|
// structure. We also want to support variable sized structures.
|
|
// The minimum must be sizeof(MODEMSETTINGS).)
|
|
cbRequiredSize = cbData + CB_MODEMSETTINGS_OVERHEAD;
|
|
|
|
// Is the size in the registry okay?
|
|
if (*pdwSize < cbRequiredSize)
|
|
{
|
|
// No
|
|
dwRet = ERROR_INSUFFICIENT_BUFFER;
|
|
*pdwSize = cbRequiredSize;
|
|
}
|
|
else
|
|
{
|
|
// Yes; get the MODEMSETTINGS from the registry
|
|
// Set the fields whose values are *not* in the registry
|
|
pms->dwActualSize = cbRequiredSize;
|
|
pms->dwRequiredSize = cbRequiredSize;
|
|
pms->dwDevSpecificOffset = 0;
|
|
pms->dwDevSpecificSize = 0;
|
|
|
|
dwRet = RegQueryValueEx(hkey, c_szDefault, NULL, NULL,
|
|
(LPBYTE)&pms->dwCallSetupFailTimer, &cbData);
|
|
pms->dwInactivityTimeout *= GetInactivityTimeoutScale(hkey);
|
|
|
|
*pdwSize = cbData + CB_MODEMSETTINGS_OVERHEAD;
|
|
}
|
|
}
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
#ifdef VOICE
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Get the voice settings from the registry. This sort
|
|
of info is not stored in the MODEMSETTINGS struct.
|
|
|
|
If this modem supports voice features, *puFlags is
|
|
updated to reflect those settings. Otherwise, *puFlags
|
|
is left alone.
|
|
|
|
Returns: One of the ERROR_ values
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE RegQueryVoiceSettings(
|
|
HKEY hkeyDrv,
|
|
LPUINT puFlags, // Out: MIF_* values
|
|
PVOICEFEATURES pvs)
|
|
{
|
|
#ifndef VOICEPROF_CLASS8ENABLED
|
|
#define VOICEPROF_CLASS8ENABLED 0x00000001L
|
|
#define VOICEPROF_NO_DIST_RING 0x00001000L
|
|
#define VOICEPROF_NO_CHEAP_RING 0x00002000L
|
|
#endif
|
|
|
|
DWORD dwRet;
|
|
DWORD cbData;
|
|
DWORD dwRegType;
|
|
DWORD dwVoiceProfile;
|
|
VOICEFEATURES vsT;
|
|
|
|
ASSERT(pvs);
|
|
ASSERT(puFlags);
|
|
|
|
|
|
// Init to default values
|
|
ZeroInit(pvs);
|
|
pvs->cbSize = sizeof(*pvs);
|
|
// (Everything else is left as 0)
|
|
|
|
|
|
ClearFlag(*puFlags, MIF_CALL_FWD_SUPPORT | MIF_DIST_RING_SUPPORT | MIF_CHEAP_RING_SUPPORT);
|
|
|
|
// Does this modem support voice features?
|
|
cbData = sizeof(dwVoiceProfile);
|
|
dwRet = RegQueryValueEx(hkeyDrv, c_szVoiceProfile, NULL, &dwRegType, (LPBYTE)&dwVoiceProfile, &cbData);
|
|
|
|
if (ERROR_SUCCESS == dwRet && REG_BINARY == dwRegType)
|
|
{
|
|
if (IsFlagSet(dwVoiceProfile, VOICEPROF_CLASS8ENABLED))
|
|
{
|
|
SetFlag(*puFlags, MIF_CALL_FWD_SUPPORT);
|
|
}
|
|
|
|
if (IsFlagClear(dwVoiceProfile, VOICEPROF_NO_DIST_RING))
|
|
{
|
|
SetFlag(*puFlags, MIF_DIST_RING_SUPPORT);
|
|
|
|
if (IsFlagClear(dwVoiceProfile, VOICEPROF_NO_CHEAP_RING))
|
|
{
|
|
// Yes, we're cheap
|
|
SetFlag(*puFlags, MIF_CHEAP_RING_SUPPORT);
|
|
}
|
|
}
|
|
|
|
|
|
// Are the voice settings here?
|
|
cbData = sizeof(vsT);
|
|
dwRet = RegQueryValueEx(hkeyDrv, c_szVoice, NULL, &dwRegType, (LPBYTE)&vsT, &cbData);
|
|
if (ERROR_SUCCESS == dwRet && REG_BINARY == dwRegType &&
|
|
sizeof(vsT) == vsT.cbSize && sizeof(vsT) == cbData)
|
|
{
|
|
// Yes
|
|
*pvs = vsT;
|
|
}
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
#endif // VOICE
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Get global modem info from the registry. This sort
|
|
of info is not stored in the MODEMSETTINGS struct.
|
|
|
|
Returns: One of the ERROR_ values
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE RegQueryGlobalModemInfo(
|
|
LPFINDDEV pfd,
|
|
LPGLOBALINFO pglobal)
|
|
{
|
|
DWORD dwRet;
|
|
DWORD cbData;
|
|
BYTE bCheck;
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
TCHAR const c_szPortConfigDialog[] = TEXT("PortConfigDialog");
|
|
#pragma data_seg()
|
|
|
|
ASSERT(pfd);
|
|
ASSERT(pglobal);
|
|
|
|
pglobal->cbSize = sizeof(*pglobal);
|
|
|
|
// Get the port name. There are two places the port name can be:
|
|
//
|
|
// 1) DriverKey\AttachedTo
|
|
// This is for internal, external or null modems. This
|
|
// port can be changed via the property sheet.
|
|
//
|
|
// 2) DriverKey\PortName
|
|
// This is for PCMCIA modems. This CANNOT be changed via
|
|
// the property sheet. Only VCOMM sets this.
|
|
//
|
|
// BUGBUG (scotth): In Win95, this value is under the
|
|
// DeviceKey. We should lobby this to be changed to
|
|
// the DriverKey.
|
|
|
|
// Does this modem have a PortName value?
|
|
cbData = sizeof(pglobal->szPortName);
|
|
dwRet = RegQueryValueEx(pfd->hkeyDrv, c_szPortName, NULL, NULL,
|
|
(LPBYTE)pglobal->szPortName, &cbData);
|
|
|
|
if (ERROR_SUCCESS != dwRet)
|
|
{
|
|
// No; get the AttachedTo value
|
|
cbData = sizeof(pglobal->szPortName);
|
|
dwRet = RegQueryValueEx(pfd->hkeyDrv, c_szAttachedTo, NULL, NULL,
|
|
(LPBYTE)pglobal->szPortName, &cbData);
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
DWORD dwBusType;
|
|
|
|
if ( !CplDiGetBusType(pfd->hdi, &pfd->devData, &dwBusType) )
|
|
{
|
|
dwRet = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
// Is the device Root-enumerated?
|
|
if (BUS_TYPE_ROOT == dwBusType)
|
|
{
|
|
// Yes; the port can be changed by the user
|
|
ClearFlag(pglobal->uFlags, MIF_PORT_IS_FIXED);
|
|
}
|
|
else
|
|
{
|
|
// No; the port cannot be changed
|
|
SetFlag(pglobal->uFlags, MIF_PORT_IS_FIXED);
|
|
}
|
|
|
|
// Get the logging value
|
|
cbData = sizeof(bCheck);
|
|
if (ERROR_SUCCESS != RegQueryValueEx(pfd->hkeyDrv, c_szLogging, NULL,
|
|
NULL, (LPBYTE)&bCheck, &cbData))
|
|
{
|
|
// Default to OFF.
|
|
ClearFlag(pglobal->uFlags, MIF_ENABLE_LOGGING);
|
|
}
|
|
else
|
|
{
|
|
if (bCheck)
|
|
SetFlag(pglobal->uFlags, MIF_ENABLE_LOGGING);
|
|
else
|
|
ClearFlag(pglobal->uFlags, MIF_ENABLE_LOGGING);
|
|
}
|
|
|
|
// Get the user init string
|
|
cbData = sizeof(pglobal->szUserInit);
|
|
if (ERROR_SUCCESS != RegQueryValueEx(pfd->hkeyDrv, c_szUserInit, NULL,
|
|
NULL, (LPBYTE)pglobal->szUserInit, &cbData))
|
|
{
|
|
// Or default to null string
|
|
*pglobal->szUserInit = '\0';
|
|
}
|
|
|
|
#ifdef WIN95
|
|
|
|
// Does this modem use a custom port?
|
|
cbData = sizeof(szPath);
|
|
if (IsFlagSet(pglobal->uFlags, MIF_PORT_IS_FIXED))
|
|
{
|
|
// (look in same devnode as modem for PortConfigDialog)
|
|
if (ERROR_SUCCESS == RegQueryValueEx(pfd->hkeyDrv, c_szPortConfigDialog,
|
|
NULL, NULL, szPath, &cbData) &&
|
|
!IsSzEqual(c_szSerialUI, szPath))
|
|
{
|
|
// Yes
|
|
SetFlag(pglobal->uFlags, MIF_PORT_IS_CUSTOM);
|
|
|
|
TRACE_MSG(TF_GENERAL, "Modem is connected to a custom port");
|
|
}
|
|
else
|
|
{
|
|
// No special config DLL for this port.
|
|
ClearFlag(pglobal->uFlags, MIF_PORT_IS_CUSTOM);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// (look in port's devnode for ConfigDialog)
|
|
LPFINDDEV pfdPort;
|
|
LPCTSTR pszPortName = pglobal->szPortName;
|
|
|
|
if (FindDev_Create(&pfdPort, c_pguidPort, c_szFriendlyName, pszPortName) ||
|
|
FindDev_Create(&pfdPort, c_pguidPort, c_szPortName, pszPortName))
|
|
{
|
|
if (ERROR_SUCCESS == RegQueryValueEx(pfdPort->hkeyDrv,
|
|
c_szConfigDialog, NULL, NULL, szPath, &cbData) &&
|
|
!IsSzEqual(c_szSerialUI, szPath))
|
|
{
|
|
// Yes
|
|
SetFlag(pglobal->uFlags, MIF_PORT_IS_CUSTOM);
|
|
|
|
TRACE_MSG(TF_GENERAL, "Modem is connected to a custom port");
|
|
}
|
|
else
|
|
{
|
|
// No special config DLL for this port.
|
|
ClearFlag(pglobal->uFlags, MIF_PORT_IS_CUSTOM);
|
|
}
|
|
FindDev_Destroy(pfdPort);
|
|
}
|
|
else
|
|
{
|
|
// Should not get here
|
|
ASSERT(0);
|
|
ClearFlag(pglobal->uFlags, MIF_PORT_IS_CUSTOM);
|
|
}
|
|
}
|
|
|
|
#else // WIN95
|
|
|
|
// For NT, there is not custom port support
|
|
ClearFlag(pglobal->uFlags, MIF_PORT_IS_CUSTOM);
|
|
|
|
#endif // WIN95
|
|
|
|
// Get the device type
|
|
cbData = sizeof(pglobal->nDeviceType);
|
|
dwRet = RegQueryValueEx(pfd->hkeyDrv, c_szDeviceType, NULL, NULL,
|
|
(LPBYTE)&pglobal->nDeviceType, &cbData);
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
// Get the properties (a portion of the MODEMDEVCAPS structure)
|
|
cbData = sizeof(pglobal->devcaps);
|
|
dwRet = RegQueryValueEx(pfd->hkeyDrv, c_szDeviceCaps, NULL, NULL,
|
|
(LPBYTE)&pglobal->devcaps, &cbData);
|
|
pglobal->devcaps.dwInactivityTimeout *= GetInactivityTimeoutScale(pfd->hkeyDrv);
|
|
}
|
|
|
|
#ifdef VOICE
|
|
// Get the Voice data
|
|
dwRet = RegQueryVoiceSettings(pfd->hkeyDrv, &pglobal->uFlags, &pglobal->vs);
|
|
#endif
|
|
}
|
|
}
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Initialize the modem info for a modem device.
|
|
|
|
Returns: One of the ERROR_ values
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE InitializeModemInfo(
|
|
LPMODEMINFO pmi,
|
|
LPFINDDEV pfd,
|
|
LPCTSTR pszFriendlyName,
|
|
LPCOMMCONFIG pcc,
|
|
LPGLOBALINFO pglobal)
|
|
{
|
|
LPMODEMSETTINGS pms;
|
|
|
|
ASSERT(pmi);
|
|
ASSERT(pfd);
|
|
ASSERT(pszFriendlyName);
|
|
ASSERT(pcc);
|
|
ASSERT(pglobal);
|
|
|
|
// Read-only fields
|
|
pmi->pcc = pcc;
|
|
pmi->pglobal = pglobal;
|
|
pmi->pfd = pfd;
|
|
|
|
// Copy data to the working buffer
|
|
pms = PmsFromPcc(pcc);
|
|
|
|
BltByte(&pmi->dcb, &pcc->dcb, sizeof(WIN32DCB));
|
|
BltByte(&pmi->ms, pms, sizeof(MODEMSETTINGS));
|
|
|
|
lstrcpyn(pmi->szFriendlyName, pszFriendlyName, SIZECHARS(pmi->szFriendlyName));
|
|
|
|
pmi->nDeviceType = pglobal->nDeviceType;
|
|
pmi->uFlags = pglobal->uFlags;
|
|
pmi->devcaps = pglobal->devcaps;
|
|
|
|
lstrcpy(pmi->szPortName, pglobal->szPortName);
|
|
lstrcpy(pmi->szUserInit, pglobal->szUserInit);
|
|
|
|
DEBUG_CODE( DumpModemSettings(pms); )
|
|
DEBUG_CODE( DumpDCB(&pcc->dcb); )
|
|
DEBUG_CODE( DumpDevCaps(&pmi->devcaps); )
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Set global modem info in the registry. This sort
|
|
of info is not stored in the MODEMSETTINGS struct.
|
|
|
|
Returns: One of ERROR_
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE RegSetGlobalModemInfo(
|
|
HKEY hkeyDrv,
|
|
LPGLOBALINFO pglobal,
|
|
LPMODEMINFO pmi)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
ASSERT(sizeof(*pglobal) == pglobal->cbSize);
|
|
|
|
TRACE_MSG(TF_GENERAL, "Writing global modem info to registry");
|
|
|
|
if (sizeof(*pglobal) == pglobal->cbSize)
|
|
{
|
|
if (IsFlagSet(pglobal->uFlags, MIF_PORTNAME_CHANGED))
|
|
{
|
|
// Only write the port name if it is stored in the AttachedTo
|
|
// field.
|
|
if (IsFlagClear(pglobal->uFlags, MIF_PORT_IS_FIXED))
|
|
{
|
|
// Save the port name
|
|
RegSetValueEx(hkeyDrv, c_szAttachedTo, 0, REG_SZ,
|
|
(LPBYTE)pglobal->szPortName,
|
|
CbFromCch(lstrlen(pglobal->szPortName)+1));
|
|
}
|
|
}
|
|
|
|
if (IsFlagSet(pglobal->uFlags, MIF_USERINIT_CHANGED))
|
|
{
|
|
// Change the user init string
|
|
RegSetValueEx(hkeyDrv, c_szUserInit, 0, REG_SZ,
|
|
(LPBYTE)pglobal->szUserInit,
|
|
CbFromCch(lstrlen(pglobal->szUserInit)+1));
|
|
}
|
|
|
|
if (IsFlagSet(pglobal->uFlags, MIF_LOGGING_CHANGED))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szFile[MAXMEDLEN];
|
|
BOOL bCheck = IsFlagSet(pglobal->uFlags, MIF_ENABLE_LOGGING);
|
|
|
|
// Change the logging value
|
|
RegSetValueEx(hkeyDrv, c_szLogging, 0, REG_BINARY,
|
|
(LPBYTE)&bCheck, sizeof(BYTE));
|
|
|
|
// Set the path of the modem log
|
|
GetWindowsDirectory(szPath, SIZECHARS(szPath));
|
|
lstrcat(szPath, TEXT("\\ModemLog_"));
|
|
lstrcat(szPath,pmi->szFriendlyName);
|
|
lstrcat(szPath,TEXT(".txt"));
|
|
// lstrcat(szPath, SzFromIDS(g_hinst, IDS_LOGFILE, szFile, SIZECHARS(szFile)));
|
|
RegSetValueEx(hkeyDrv, c_szLoggingPath, 0, REG_SZ,
|
|
(LPBYTE)szPath, CbFromCch(lstrlen(szPath)+1));
|
|
}
|
|
|
|
#ifdef VOICE
|
|
RegSetValueEx(hkeyDrv, c_szVoice, 0, REG_BINARY,
|
|
(LPBYTE)&pglobal->vs, pglobal->vs.cbSize);
|
|
#endif
|
|
|
|
dwRet = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
dwRet = ERROR_INVALID_PARAMETER;
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Set dev settings info in the registry, after checking
|
|
for legal values.
|
|
|
|
Returns: One of ERROR_
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE RegSetModemSettings(
|
|
HKEY hkeyDrv,
|
|
LPMODEMSETTINGS pms)
|
|
{
|
|
DWORD dwRet;
|
|
DWORD cbData;
|
|
DWORD dwInactivityScale;
|
|
DWORD dwInactivityTimeoutTemp;
|
|
REGDEVCAPS regdevcaps;
|
|
REGDEVSETTINGS regdevsettings;
|
|
|
|
// Read in the Properties line from the registry.
|
|
cbData = sizeof(REGDEVCAPS);
|
|
dwRet = RegQueryValueEx(hkeyDrv, c_szDeviceCaps, NULL, NULL,
|
|
(LPBYTE)®devcaps, &cbData);
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
// Read in existing regdevsettings, so that we can handle error cases below.
|
|
cbData = sizeof(REGDEVSETTINGS);
|
|
dwRet = RegQueryValueEx(hkeyDrv, c_szDefault, NULL, NULL,
|
|
(LPBYTE)®devsettings, &cbData);
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
// copy new REGDEVSETTINGS while checking validity of each option (ie, is the option available?)
|
|
// dwCallSetupFailTimer - MIN_CALL_SETUP_FAIL_TIMER <= xxx <= ModemDevCaps->dwCallSetupFailTimer
|
|
if (pms->dwCallSetupFailTimer > regdevcaps.dwCallSetupFailTimer) // max
|
|
{
|
|
regdevsettings.dwCallSetupFailTimer = regdevcaps.dwCallSetupFailTimer;
|
|
}
|
|
else
|
|
{
|
|
if (pms->dwCallSetupFailTimer < MIN_CALL_SETUP_FAIL_TIMER) // min
|
|
{
|
|
regdevsettings.dwCallSetupFailTimer = MIN_CALL_SETUP_FAIL_TIMER;
|
|
}
|
|
else
|
|
{
|
|
regdevsettings.dwCallSetupFailTimer = pms->dwCallSetupFailTimer; // dest = src
|
|
}
|
|
}
|
|
|
|
// convert dwInactivityTimeout to registry scale
|
|
dwInactivityScale = GetInactivityTimeoutScale(hkeyDrv);
|
|
dwInactivityTimeoutTemp = pms->dwInactivityTimeout / dwInactivityScale +
|
|
(pms->dwInactivityTimeout % dwInactivityScale ? 1 : 0);
|
|
|
|
// dwInactivityTimeout - MIN_INACTIVITY_TIMEOUT <= xxx <= ModemDevCaps->dwInactivityTimeout
|
|
if (dwInactivityTimeoutTemp > regdevcaps.dwInactivityTimeout) // max
|
|
{
|
|
regdevsettings.dwInactivityTimeout = regdevcaps.dwInactivityTimeout;
|
|
}
|
|
else
|
|
{
|
|
if (dwInactivityTimeoutTemp < MIN_INACTIVITY_TIMEOUT) // min
|
|
{
|
|
regdevsettings.dwInactivityTimeout = MIN_INACTIVITY_TIMEOUT;
|
|
}
|
|
else
|
|
{
|
|
regdevsettings.dwInactivityTimeout = dwInactivityTimeoutTemp; // dest = src
|
|
}
|
|
}
|
|
|
|
// dwSpeakerVolume - check to see if selection is possible
|
|
if ((1 << pms->dwSpeakerVolume) & regdevcaps.dwSpeakerVolume)
|
|
{
|
|
regdevsettings.dwSpeakerVolume = pms->dwSpeakerVolume;
|
|
}
|
|
|
|
// dwSpeakerMode - check to see if selection is possible
|
|
if ((1 << pms->dwSpeakerMode) & regdevcaps.dwSpeakerMode)
|
|
{
|
|
regdevsettings.dwSpeakerMode = pms->dwSpeakerMode;
|
|
}
|
|
|
|
// dwPreferredModemOptions - mask out anything we can't set
|
|
regdevsettings.dwPreferredModemOptions = pms->dwPreferredModemOptions & regdevcaps.dwModemOptions;
|
|
|
|
cbData = sizeof(REGDEVSETTINGS);
|
|
dwRet = RegSetValueEx(hkeyDrv, c_szDefault, 0, REG_BINARY,
|
|
(LPBYTE)®devsettings, cbData);
|
|
}
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Frees a modeminfo struct
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PRIVATE FreeModemInfo(
|
|
LPMODEMINFO pmi)
|
|
{
|
|
if (pmi)
|
|
{
|
|
if (pmi->pcc)
|
|
LocalFree(LOCALOF(pmi->pcc));
|
|
|
|
if (pmi->pglobal)
|
|
LocalFree(LOCALOF(pmi->pglobal));
|
|
|
|
if (pmi->pfd)
|
|
FindDev_Destroy(pmi->pfd);
|
|
|
|
LocalFree(LOCALOF(pmi));
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Release the data associated with the General page
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
UINT CALLBACK GeneralPageCallback(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
LPPROPSHEETPAGE ppsp)
|
|
{
|
|
if (PSPCB_RELEASE == uMsg)
|
|
{
|
|
LPMODEMINFO pmi = (LPMODEMINFO)ppsp->lParam;
|
|
LPCOMMCONFIG pcc;
|
|
LPMODEMSETTINGS pms;
|
|
LPGLOBALINFO pglobal;
|
|
|
|
ASSERT(pmi);
|
|
|
|
pcc = pmi->pcc;
|
|
ASSERT(pcc);
|
|
|
|
pms = PmsFromPcc(pcc);
|
|
|
|
pglobal = pmi->pglobal;
|
|
ASSERT(pglobal);
|
|
|
|
if (IDOK == pmi->idRet)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
// Save the changes back to the commconfig struct
|
|
TRACE_MSG(TF_GENERAL, "Copying DCB and MODEMSETTING back to COMMCONFIG");
|
|
|
|
BltByte(pms, &pmi->ms, sizeof(MODEMSETTINGS));
|
|
BltByte(&pcc->dcb, &pmi->dcb, sizeof(WIN32DCB));
|
|
|
|
// Write the global info now, since it is getting nuked.
|
|
pglobal->uFlags = pmi->uFlags;
|
|
lstrcpy(pglobal->szPortName, pmi->szPortName);
|
|
lstrcpy(pglobal->szUserInit, pmi->szUserInit);
|
|
|
|
dwRet = RegSetGlobalModemInfo(pmi->pfd->hkeyDrv, pglobal, pmi);
|
|
ASSERT(ERROR_SUCCESS == dwRet);
|
|
|
|
DEBUG_CODE( DumpModemSettings(pms); )
|
|
DEBUG_CODE( DumpDCB(&pcc->dcb); )
|
|
|
|
// Are we releasing from the Device Mgr?
|
|
if (IsFlagSet(pmi->uFlags, MIF_FROM_DEVMGR))
|
|
{
|
|
// Yes; save the commconfig now as well
|
|
drvSetDefaultCommConfigW(pmi->szFriendlyName, pcc, pcc->dwSize);
|
|
|
|
// Free the modeminfo struct now only when called from the
|
|
// Device Mgr
|
|
FreeModemInfo(pmi);
|
|
}
|
|
}
|
|
|
|
TRACE_MSG(TF_GENERAL, "Releasing the General page");
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Add the General modems page. The pmi is the pointer
|
|
to the modeminfo buffer which we can edit.
|
|
|
|
Returns: ERROR_ values
|
|
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE AddGeneralPage(
|
|
LPMODEMINFO pmi,
|
|
LPFNADDPROPSHEETPAGE pfnAdd,
|
|
LPARAM lParam)
|
|
{
|
|
DWORD dwRet = ERROR_NOT_ENOUGH_MEMORY;
|
|
PROPSHEETPAGE psp;
|
|
HPROPSHEETPAGE hpage;
|
|
TCHAR sz[MAXMEDLEN];
|
|
|
|
ASSERT(pmi);
|
|
ASSERT(pfnAdd);
|
|
|
|
// Add the Port Settings property page
|
|
//
|
|
psp.dwSize = sizeof(PROPSHEETPAGE);
|
|
psp.dwFlags = PSP_USECALLBACK;
|
|
psp.hInstance = g_hinst;
|
|
psp.pszTemplate = MAKEINTRESOURCE(IDD_GENERAL);
|
|
psp.pfnDlgProc = Gen_WrapperProc;
|
|
psp.lParam = (LPARAM)pmi;
|
|
psp.pfnCallback = GeneralPageCallback;
|
|
psp.pcRefParent = NULL;
|
|
|
|
// Is this page added to the device mgr properties?
|
|
if (IsFlagSet(pmi->uFlags, MIF_FROM_DEVMGR))
|
|
{
|
|
// Yes; change name from "General"
|
|
psp.dwFlags |= PSP_USETITLE;
|
|
psp.pszTitle = SzFromIDS(g_hinst, IDS_CAP_GENERAL, sz, SIZECHARS(sz));
|
|
}
|
|
|
|
hpage = CreatePropertySheetPage(&psp);
|
|
if (hpage)
|
|
{
|
|
if (!pfnAdd(hpage, lParam))
|
|
DestroyPropertySheetPage(hpage);
|
|
else
|
|
dwRet = NO_ERROR;
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Add a page. The pmi is the pointer to the modeminfo
|
|
buffer which we can edit.
|
|
|
|
Returns: ERROR_ values
|
|
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE AddPage(
|
|
LPMODEMINFO pmi,
|
|
LPCTSTR pszTemplate,
|
|
DLGPROC pfnDlgProc,
|
|
LPFNADDPROPSHEETPAGE pfnAdd,
|
|
LPARAM lParam)
|
|
{
|
|
DWORD dwRet = ERROR_NOT_ENOUGH_MEMORY;
|
|
PROPSHEETPAGE psp;
|
|
HPROPSHEETPAGE hpage;
|
|
|
|
ASSERT(pmi);
|
|
ASSERT(pfnAdd);
|
|
|
|
// Add the Port Settings property page
|
|
//
|
|
psp.dwSize = sizeof(PROPSHEETPAGE);
|
|
psp.dwFlags = PSP_DEFAULT;
|
|
psp.hInstance = g_hinst;
|
|
psp.pszTemplate = pszTemplate;
|
|
psp.pfnDlgProc = pfnDlgProc;
|
|
psp.lParam = (LPARAM)pmi;
|
|
|
|
hpage = CreatePropertySheetPage(&psp);
|
|
if (hpage)
|
|
{
|
|
if (!pfnAdd(hpage, lParam))
|
|
DestroyPropertySheetPage(hpage);
|
|
else
|
|
dwRet = NO_ERROR;
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Add extra pages.
|
|
|
|
Returns: ERROR_ values
|
|
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE AddExtraPages(
|
|
LPPROPSHEETPAGE pPages,
|
|
DWORD cPages,
|
|
LPFNADDPROPSHEETPAGE pfnAdd,
|
|
LPARAM lParam)
|
|
{
|
|
HPROPSHEETPAGE hpage;
|
|
UINT i;
|
|
|
|
ASSERT(pPages);
|
|
ASSERT(cPages);
|
|
ASSERT(pfnAdd);
|
|
|
|
for (i = 0; i < cPages; i++, pPages++)
|
|
{
|
|
// Add the extra property page
|
|
//
|
|
if (pPages->dwSize == sizeof(PROPSHEETPAGE))
|
|
{
|
|
hpage = CreatePropertySheetPage(pPages);
|
|
if (hpage)
|
|
{
|
|
if (!pfnAdd(hpage, lParam))
|
|
DestroyPropertySheetPage(hpage);
|
|
}
|
|
};
|
|
};
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Function that is called by EnumPropPages entry-point to
|
|
add property pages.
|
|
|
|
Returns: TRUE on success
|
|
FALSE on failure
|
|
|
|
Cond: --
|
|
*/
|
|
BOOL WINAPI AddInstallerPropPage(
|
|
HPROPSHEETPAGE hPage,
|
|
LPARAM lParam)
|
|
{
|
|
PROPSHEETHEADER FAR * ppsh = (PROPSHEETHEADER FAR *)lParam;
|
|
|
|
if (ppsh->nPages < MAX_PROP_PAGES)
|
|
{
|
|
ppsh->phpage[ppsh->nPages] = hPage;
|
|
++ppsh->nPages;
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Show the properties of a modem
|
|
|
|
Returns: winerror
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE DoProperties(
|
|
HWND hwndParent,
|
|
LPMODEMINFO pmi,
|
|
LPPROPSHEETPAGE pPages, // Optional; may be NULL
|
|
DWORD cPages)
|
|
{
|
|
DWORD dwRet;
|
|
PROPSHEETHEADER psh;
|
|
HPROPSHEETPAGE hpsPages[MAX_PROP_PAGES];
|
|
|
|
ASSERT(pmi);
|
|
|
|
// Initialize the PropertySheet Header
|
|
psh.dwSize = sizeof(psh);
|
|
psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
|
|
psh.hwndParent = hwndParent;
|
|
psh.hInstance = g_hinst;
|
|
psh.nPages = 0;
|
|
psh.nStartPage = 0;
|
|
psh.phpage = (HPROPSHEETPAGE FAR *)hpsPages;
|
|
psh.pszCaption = pmi->szFriendlyName;
|
|
|
|
dwRet = AddGeneralPage(pmi, AddInstallerPropPage, (LPARAM)&psh);
|
|
if (NO_ERROR == dwRet)
|
|
{
|
|
dwRet = AddPage(pmi,
|
|
MAKEINTRESOURCE(IDD_MDMSETTINGS),
|
|
Sett_WrapperProc,
|
|
AddInstallerPropPage,
|
|
(LPARAM)&psh);
|
|
if (NO_ERROR == dwRet)
|
|
{
|
|
// Add extra pages if any
|
|
if ((cPages != 0) && (pPages != NULL))
|
|
{
|
|
AddExtraPages(pPages, cPages, AddInstallerPropPage, (LPARAM)&psh);
|
|
}
|
|
|
|
#ifdef VOICE
|
|
if (IsFlagSet(pmi->uFlags, MIF_DIST_RING_SUPPORT))
|
|
{
|
|
if (IsFlagSet(pmi->uFlags, MIF_CHEAP_RING_SUPPORT))
|
|
{
|
|
AddPage(pmi, MAKEINTRESOURCE(IDD_CHEAPRING),
|
|
CheapRing_WrapperProc, AddInstallerPropPage,
|
|
(LPARAM)&psh);
|
|
}
|
|
else
|
|
{
|
|
AddPage(pmi, MAKEINTRESOURCE(IDD_RING),
|
|
Ring_WrapperProc, AddInstallerPropPage,
|
|
(LPARAM)&psh);
|
|
}
|
|
}
|
|
|
|
|
|
if (IsFlagSet(pmi->uFlags, MIF_CALL_FWD_SUPPORT))
|
|
{
|
|
AddPage(pmi, MAKEINTRESOURCE(IDD_CALLFWD),
|
|
CallFwd_WrapperProc, AddInstallerPropPage,
|
|
(LPARAM)&psh);
|
|
}
|
|
#endif
|
|
|
|
// Show the property sheet
|
|
PropertySheet(&psh);
|
|
|
|
dwRet = (IDOK == pmi->idRet) ? NO_ERROR : ERROR_CANCELLED;
|
|
}
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Invokes the modem configuration dialog.
|
|
|
|
Returns: One of the ERROR_ values
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE MyCommConfigDialog(
|
|
LPFINDDEV pfd,
|
|
LPCTSTR pszFriendlyName,
|
|
HWND hwndOwner,
|
|
LPCOMMCONFIG pcc,
|
|
LPPROPSHEETPAGE pPages, // Optional; may be NULL
|
|
DWORD cPages)
|
|
{
|
|
DWORD dwRet;
|
|
LPMODEMINFO pmi;
|
|
LPGLOBALINFO pglobal;
|
|
|
|
ASSERT(pfd);
|
|
// (Wrapper should have checked these first)
|
|
ASSERT(pszFriendlyName);
|
|
ASSERT(pcc);
|
|
ASSERT(CB_COMMCONFIGSIZE <= pcc->dwSize);
|
|
|
|
// Allocate the working buffer
|
|
pmi = (LPMODEMINFO)LocalAlloc(LPTR, sizeof(*pmi));
|
|
if (pmi)
|
|
{
|
|
// Create a structure for the global modem info
|
|
pglobal = (LPGLOBALINFO)LocalAlloc(LPTR, LOWORD(sizeof(GLOBALINFO)));
|
|
if (pglobal)
|
|
{
|
|
dwRet = RegQueryGlobalModemInfo(pfd, pglobal);
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
InitializeModemInfo(pmi, pfd, pszFriendlyName, pcc, pglobal);
|
|
|
|
DEBUG_CODE( DumpDCB(&pcc->dcb); )
|
|
|
|
dwRet = DoProperties(hwndOwner, pmi, pPages, cPages);
|
|
}
|
|
else
|
|
{
|
|
FindDev_Destroy(pfd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FindDev_Destroy(pfd);
|
|
dwRet = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FindDev_Destroy(pfd);
|
|
dwRet = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
|
|
// Clear the pcc field so FreeModemInfo does not prematurely
|
|
// free it, since we did not allocate it.
|
|
pmi->pcc = NULL;
|
|
FreeModemInfo(pmi);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
#ifdef WIN95
|
|
|
|
// The Device Manager allows DLLs to add pages to the properties
|
|
// of a device. EnumPropPages is the entry-point that it would
|
|
// call to add pages.
|
|
//
|
|
// This is not implemented in NT.
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Derives a MODEMINFO struct from a device info.
|
|
|
|
Returns: TRUE on success
|
|
|
|
Cond: --
|
|
*/
|
|
BOOL PRIVATE DeviceInfoToModemInfo(
|
|
LPDEVICE_INFO pdi,
|
|
LPMODEMINFO pmi)
|
|
{
|
|
BOOL bRet;
|
|
COMMCONFIG ccDummy;
|
|
LPCOMMCONFIG pcommconfig;
|
|
LPGLOBALINFO pglobal;
|
|
LPFINDDEV pfd;
|
|
DWORD cbSize;
|
|
DWORD cbData;
|
|
TCHAR szFriendly[MAXFRIENDLYNAME];
|
|
|
|
// Find the device by looking for the device description. (Note the
|
|
// device description is not always the same as the friendly name.)
|
|
|
|
if (FindDev_Create(&pfd, c_pguidModem, c_szDeviceDesc, pdi->szDescription))
|
|
{
|
|
cbData = sizeof(szFriendly);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(pfd->hkeyDrv, c_szFriendlyName, NULL, NULL,
|
|
(LPBYTE)szFriendly, &cbData))
|
|
{
|
|
ccDummy.dwProviderSubType = PST_MODEM;
|
|
cbSize = sizeof(COMMCONFIG);
|
|
drvGetDefaultCommConfig(szFriendly, &ccDummy, &cbSize);
|
|
|
|
pcommconfig = (LPCOMMCONFIG)LocalAlloc(LPTR, (UINT)cbSize);
|
|
if (pcommconfig)
|
|
{
|
|
// Get the commconfig from the registry
|
|
pcommconfig->dwProviderSubType = PST_MODEM;
|
|
if (NO_ERROR == drvGetDefaultCommConfig(szFriendly,
|
|
pcommconfig, &cbSize))
|
|
{
|
|
// Create a structure for the global modem info
|
|
pglobal = (LPGLOBALINFO)LocalAlloc(LPTR, LOWORD(sizeof(GLOBALINFO)));
|
|
if (pglobal)
|
|
{
|
|
DWORD dwRet = RegQueryGlobalModemInfo(pfd, pglobal);
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
// Initialize the modem info from the commconfig
|
|
InitializeModemInfo(pmi, pfd, szFriendly, pcommconfig, pglobal);
|
|
|
|
SetFlag(pmi->uFlags, MIF_FROM_DEVMGR);
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Failure
|
|
LocalFree(LOCALOF(pcommconfig));
|
|
LocalFree(LOCALOF(pglobal));
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Failure
|
|
LocalFree(LOCALOF(pcommconfig));
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Failure
|
|
LocalFree(LOCALOF(pcommconfig));
|
|
bRet = FALSE;
|
|
}
|
|
|
|
// pcommconfig and pglobnal are freed in GeneralPageCallback
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
|
|
// pfd is destroyed in GeneralPageCallback
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: EnumDevicePropPages entry-point. This entry-point
|
|
gets called only when the Device Manager asks for
|
|
advanced property pages.
|
|
|
|
Returns: TRUE on success
|
|
FALSE if pages could not be added
|
|
Cond: --
|
|
*/
|
|
BOOL WINAPI EnumPropPages(
|
|
LPDEVICE_INFO pdi,
|
|
LPFNADDPROPSHEETPAGE pfnAdd,
|
|
LPARAM lParam) // Don't touch the lParam value, just pass it on!
|
|
{
|
|
BOOL bRet = FALSE;
|
|
LPMODEMINFO pmi;
|
|
|
|
DBG_ENTER(EnumPropPages);
|
|
|
|
ASSERT(pdi);
|
|
ASSERT(pfnAdd);
|
|
|
|
pmi = (LPMODEMINFO)LocalAlloc(LPTR, sizeof(*pmi));
|
|
if (pmi)
|
|
{
|
|
// Convert the device info struct to a modeminfo.
|
|
bRet = DeviceInfoToModemInfo(pdi, pmi);
|
|
if (bRet)
|
|
{
|
|
AddGeneralPage(pmi, pfnAdd, lParam);
|
|
AddPage(pmi, MAKEINTRESOURCE(IDD_MDMSETTINGS), Sett_WrapperProc, pfnAdd, lParam);
|
|
|
|
#ifdef VOICE
|
|
if (IsFlagSet(pmi->uFlags, MIF_DIST_RING_SUPPORT))
|
|
{
|
|
if (IsFlagSet(pmi->uFlags, MIF_CHEAP_RING_SUPPORT))
|
|
{
|
|
AddPage(pmi, MAKEINTRESOURCE(IDD_CHEAPRING),
|
|
CheapRing_WrapperProc, AddInstallerPropPage,
|
|
lParam);
|
|
}
|
|
else
|
|
{
|
|
AddPage(pmi, MAKEINTRESOURCE(IDD_RING),
|
|
Ring_WrapperProc, AddInstallerPropPage,
|
|
lParam);
|
|
}
|
|
}
|
|
|
|
if (IsFlagSet(pmi->uFlags, MIF_CALL_FWD_SUPPORT))
|
|
{
|
|
AddPage(pmi, MAKEINTRESOURCE(IDD_CALLFWD),
|
|
CallFwd_WrapperProc, AddInstallerPropPage,
|
|
lParam);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Failed
|
|
FreeModemInfo(pmi);
|
|
}
|
|
// pmi is freed in GeneralPageCallback
|
|
}
|
|
|
|
DBG_EXIT_BOOL(EnumPropPages, bRet);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
#endif // WIN95
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Gets the default COMMCONFIG for the specified device.
|
|
This API doesn't require a handle.
|
|
|
|
We get the info from the registry.
|
|
|
|
Returns: One of the ERROR_ values
|
|
|
|
Cond: --
|
|
*/
|
|
DWORD APIENTRY
|
|
UnimodemGetDefaultCommConfig(
|
|
HKEY hKey,
|
|
LPCOMMCONFIG pcc,
|
|
LPDWORD pdwSize)
|
|
{
|
|
DWORD dwRet;
|
|
DWORD cbSizeMS;
|
|
DWORD cbRequired;
|
|
|
|
ASSERT(pcc);
|
|
ASSERT(pdwSize);
|
|
|
|
// (The provider size is the size of MODEMSETTINGS and its
|
|
// private data.)
|
|
|
|
if (CB_PRIVATESIZE > *pdwSize) // Prevent unsigned rollover
|
|
cbSizeMS = 0;
|
|
else
|
|
cbSizeMS = *pdwSize - CB_PRIVATESIZE;
|
|
|
|
dwRet = RegQueryModemSettings(hKey, PmsFromPcc(pcc), &cbSizeMS);
|
|
ASSERT(cbSizeMS >= sizeof(MODEMSETTINGS));
|
|
|
|
// Is the provided size too small?
|
|
cbRequired = CB_PRIVATESIZE + cbSizeMS;
|
|
|
|
if (cbRequired > *pdwSize)
|
|
{
|
|
// Yes
|
|
dwRet = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
// Ask for a size to fit the new format
|
|
*pdwSize = cbRequired;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
// No
|
|
#ifdef DEBUG
|
|
DumpModemSettings(PmsFromPcc(pcc));
|
|
#endif
|
|
|
|
*pdwSize = cbRequired;
|
|
|
|
// Initialize the commconfig structure
|
|
pcc->dwSize = *pdwSize;
|
|
pcc->wVersion = COMMCONFIG_VERSION_1;
|
|
pcc->dwProviderSubType = PST_MODEM;
|
|
pcc->dwProviderOffset = CB_COMMCONFIG_HEADER;
|
|
pcc->dwProviderSize = cbSizeMS;
|
|
|
|
dwRet = RegQueryDCB(hKey, &pcc->dcb);
|
|
|
|
DEBUG_CODE( DumpDCB(&pcc->dcb); )
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Gets the default COMMCONFIG for the specified device.
|
|
This API doesn't require a handle.
|
|
|
|
We get the info from the registry.
|
|
|
|
Returns: One of the ERROR_ values
|
|
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE MyGetDefaultCommConfig(
|
|
LPFINDDEV pfd,
|
|
LPCTSTR pszFriendlyName,
|
|
LPCOMMCONFIG pcc,
|
|
LPDWORD pdwSize)
|
|
{
|
|
DWORD dwRet;
|
|
DWORD cbSizeMS;
|
|
DWORD cbRequired;
|
|
|
|
ASSERT(pfd);
|
|
// (Wrapper should have checked these first)
|
|
ASSERT(pszFriendlyName);
|
|
ASSERT(pcc);
|
|
ASSERT(pdwSize);
|
|
#if 0
|
|
// (The provider size is the size of MODEMSETTINGS and its
|
|
// private data.)
|
|
|
|
if (CB_PRIVATESIZE > *pdwSize) // Prevent unsigned rollover
|
|
cbSizeMS = 0;
|
|
else
|
|
cbSizeMS = *pdwSize - CB_PRIVATESIZE;
|
|
|
|
dwRet = RegQueryModemSettings(pfd->hkeyDrv, PmsFromPcc(pcc), &cbSizeMS);
|
|
ASSERT(cbSizeMS >= sizeof(MODEMSETTINGS));
|
|
|
|
// Is the provided size too small?
|
|
cbRequired = CB_PRIVATESIZE + cbSizeMS;
|
|
if (cbRequired > *pdwSize)
|
|
{
|
|
// Yes
|
|
dwRet = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
// Ask for a size to fit the new format
|
|
*pdwSize = cbRequired;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
// No
|
|
#ifdef DEBUG
|
|
DumpModemSettings(PmsFromPcc(pcc));
|
|
#endif
|
|
|
|
// Initialize the commconfig structure
|
|
pcc->dwSize = *pdwSize;
|
|
pcc->wVersion = COMMCONFIG_VERSION_1;
|
|
pcc->dwProviderSubType = PST_MODEM;
|
|
pcc->dwProviderOffset = CB_COMMCONFIG_HEADER;
|
|
pcc->dwProviderSize = cbSizeMS;
|
|
|
|
dwRet = RegQueryDCB(pfd->hkeyDrv, &pcc->dcb);
|
|
|
|
DEBUG_CODE( DumpDCB(&pcc->dcb); )
|
|
}
|
|
#endif
|
|
|
|
dwRet=UnimodemGetDefaultCommConfig(
|
|
pfd->hkeyDrv,
|
|
pcc,
|
|
pdwSize
|
|
);
|
|
|
|
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Sets the default COMMCONFIG for the specified device.
|
|
This API doesn't require a handle. This function
|
|
strictly modifies the registry. Use SetCommConfig
|
|
to set the COMMCONFIG of an open device.
|
|
|
|
If the dwSize parameter or the dwSize field are invalid
|
|
sizes (given the dwProviderSubType field in COMMCONFIG),
|
|
then this function fails.
|
|
|
|
Returns: One of the ERROR_ return values
|
|
|
|
Cond: --
|
|
*/
|
|
DWORD PRIVATE MySetDefaultCommConfig(
|
|
LPFINDDEV pfd,
|
|
LPCTSTR pszFriendlyName,
|
|
LPCOMMCONFIG pcc)
|
|
{
|
|
DWORD dwRet = ERROR_INVALID_PARAMETER;
|
|
DWORD cbData;
|
|
|
|
ASSERT(pfd);
|
|
// (Wrapper should have checked these first)
|
|
ASSERT(pszFriendlyName);
|
|
ASSERT(pcc);
|
|
ASSERT(CB_COMMCONFIGSIZE <= pcc->dwSize);
|
|
|
|
ASSERT(CB_PROVIDERSIZE <= pcc->dwProviderSize);
|
|
ASSERT(FIELDOFFSET(COMMCONFIG, wcProviderData) == pcc->dwProviderOffset);
|
|
|
|
if (CB_PROVIDERSIZE <= pcc->dwProviderSize)
|
|
{
|
|
LPMODEMSETTINGS pms = PmsFromPcc(pcc);
|
|
|
|
// Write the DCB to the driver key
|
|
cbData = sizeof(WIN32DCB);
|
|
|
|
pcc->dcb.DCBlength=cbData;
|
|
|
|
dwRet = RegSetValueEx(pfd->hkeyDrv, c_szDCB, 0, REG_BINARY,
|
|
(LPBYTE)&pcc->dcb, cbData);
|
|
|
|
TRACE_MSG(TF_GENERAL, "Writing DCB to registry");
|
|
|
|
DEBUG_CODE( DumpDCB(&pcc->dcb); )
|
|
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
TRACE_MSG(TF_GENERAL, "Writing MODEMSETTINGS to registry");
|
|
|
|
// cbData = pcc->dwProviderSize - CB_MODEMSETTINGS_OVERHEAD;
|
|
|
|
dwRet = RegSetModemSettings(pfd->hkeyDrv, pms);
|
|
|
|
DEBUG_CODE( DumpModemSettings(pms); )
|
|
}
|
|
}
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// Entry-points provided for KERNEL32 APIs
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
|
|
// BUGBUG: This function is exported for the Unimodem TAPI service
|
|
// provider's use. We should really consolidate its pages into this
|
|
// DLL.
|
|
DWORD
|
|
APIENTRY
|
|
Mdm_CommConfigDialog(
|
|
IN LPCTSTR pszFriendlyName,
|
|
IN HWND hwndOwner,
|
|
IN OUT LPCOMMCONFIG pcc,
|
|
IN LPPROPSHEETPAGE pPages, OPTIONAL
|
|
IN DWORD cPages)
|
|
{
|
|
DWORD dwRet;
|
|
LPFINDDEV pfd;
|
|
|
|
DBG_ENTER_SZ(drvCommConfigDialog, pszFriendlyName);
|
|
|
|
DEBUG_CODE( DEBUG_BREAK(BF_ONAPIENTER); )
|
|
|
|
// We support friendly names (eg, "Hayes Accura 144")
|
|
|
|
if (NULL == pszFriendlyName ||
|
|
NULL == pcc)
|
|
{
|
|
dwRet = ERROR_INVALID_PARAMETER;
|
|
}
|
|
// Is the size sufficient?
|
|
else if (CB_COMMCONFIGSIZE > pcc->dwSize)
|
|
{
|
|
// No
|
|
dwRet = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else if (FindDev_Create(&pfd, c_pguidModem, c_szFriendlyName, pszFriendlyName))
|
|
{
|
|
dwRet = MyCommConfigDialog(pfd, pszFriendlyName, hwndOwner, pcc, pPages, cPages);
|
|
|
|
// (MyCommConfigDialog freed pfd)
|
|
}
|
|
else
|
|
{
|
|
dwRet = ERROR_BADKEY;
|
|
}
|
|
|
|
DBG_EXIT_DWORD(drvCommConfigDialog, dwRet);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
#ifdef UNICODE
|
|
drvCommConfigDialogA(
|
|
IN LPCSTR pszFriendlyName,
|
|
IN HWND hwndOwner,
|
|
IN OUT LPCOMMCONFIG pcc)
|
|
#else
|
|
drvCommConfigDialogW(
|
|
IN LPCWSTR pszFriendlyName,
|
|
IN HWND hwndOwner,
|
|
IN OUT LPCOMMCONFIG pcc)
|
|
#endif
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Entry point for CommConfigDialog
|
|
|
|
Returns: standard error value in winerror.h
|
|
Cond: --
|
|
*/
|
|
DWORD
|
|
APIENTRY
|
|
drvCommConfigDialog(
|
|
IN LPCTSTR pszFriendlyName,
|
|
IN HWND hwndOwner,
|
|
IN OUT LPCOMMCONFIG pcc)
|
|
{
|
|
return Mdm_CommConfigDialog(pszFriendlyName, hwndOwner, pcc, NULL, 0);
|
|
}
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
#ifdef UNICODE
|
|
drvGetDefaultCommConfigA(
|
|
IN LPCSTR pszFriendlyName,
|
|
IN LPCOMMCONFIG pcc,
|
|
IN OUT LPDWORD pdwSize)
|
|
#else
|
|
drvGetDefaultCommConfigW(
|
|
IN LPCWSTR pszFriendlyName,
|
|
IN LPCOMMCONFIG pcc,
|
|
IN OUT LPDWORD pdwSize)
|
|
#endif
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Entry point for GetDefaultCommConfig
|
|
|
|
Returns: standard error value in winerror.h
|
|
Cond: --
|
|
*/
|
|
DWORD
|
|
APIENTRY
|
|
drvGetDefaultCommConfig(
|
|
IN LPCTSTR pszFriendlyName,
|
|
IN LPCOMMCONFIG pcc,
|
|
IN OUT LPDWORD pdwSize)
|
|
{
|
|
DWORD dwRet;
|
|
LPFINDDEV pfd;
|
|
|
|
DBG_ENTER_SZ(drvGetDefaultCommConfig, pszFriendlyName);
|
|
|
|
DEBUG_CODE( DEBUG_BREAK(BF_ONAPIENTER); )
|
|
|
|
// We support friendly names (eg, "Hayes Accura 144")
|
|
|
|
if (NULL == pszFriendlyName ||
|
|
NULL == pcc ||
|
|
NULL == pdwSize)
|
|
{
|
|
dwRet = ERROR_INVALID_PARAMETER;
|
|
}
|
|
else if (FindDev_Create(&pfd, c_pguidModem, c_szFriendlyName, pszFriendlyName))
|
|
{
|
|
dwRet = MyGetDefaultCommConfig(pfd, pszFriendlyName, pcc, pdwSize);
|
|
|
|
FindDev_Destroy(pfd);
|
|
}
|
|
else
|
|
{
|
|
dwRet = ERROR_BADKEY;
|
|
}
|
|
|
|
DBG_EXIT_DWORD(drvGetDefaultCommConfig, dwRet);
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
#ifdef UNICODE
|
|
drvSetDefaultCommConfigA(
|
|
IN LPSTR pszFriendlyName,
|
|
IN LPCOMMCONFIG pcc,
|
|
IN DWORD dwSize)
|
|
#else
|
|
drvSetDefaultCommConfigW(
|
|
IN LPWSTR pszFriendlyName,
|
|
IN LPCOMMCONFIG pcc,
|
|
IN DWORD dwSize)
|
|
#endif
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Entry point for SetDefaultCommConfig
|
|
|
|
Returns: standard error value in winerror.h
|
|
Cond: --
|
|
*/
|
|
DWORD
|
|
APIENTRY
|
|
drvSetDefaultCommConfig(
|
|
IN LPTSTR pszFriendlyName,
|
|
IN LPCOMMCONFIG pcc,
|
|
IN DWORD dwSize) // This is ignored
|
|
{
|
|
DWORD dwRet;
|
|
LPFINDDEV pfd;
|
|
|
|
// BUGBUG (scotth): it is not great that the dwSize parameter is
|
|
// ignored. It should have been used. I was young and foolish
|
|
// back when I originally implemented this. It should be reviewed
|
|
// whether to start looking at this parameter now.
|
|
|
|
DBG_ENTER_SZ(drvSetDefaultCommConfig, pszFriendlyName);
|
|
|
|
DEBUG_CODE( DEBUG_BREAK(BF_ONAPIENTER); )
|
|
|
|
// We support friendly names (eg, "Hayes Accura 144")
|
|
|
|
if (NULL == pszFriendlyName ||
|
|
NULL == pcc)
|
|
{
|
|
dwRet = ERROR_INVALID_PARAMETER;
|
|
}
|
|
// Is the size sufficient?
|
|
else if (CB_COMMCONFIGSIZE > pcc->dwSize)
|
|
{
|
|
// No
|
|
dwRet = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else if (FindDev_Create(&pfd, c_pguidModem, c_szFriendlyName, pszFriendlyName))
|
|
{
|
|
dwRet = MySetDefaultCommConfig(pfd, pszFriendlyName, pcc);
|
|
|
|
FindDev_Destroy(pfd);
|
|
}
|
|
else
|
|
{
|
|
dwRet = ERROR_BADKEY;
|
|
}
|
|
|
|
DBG_EXIT_DWORD(drvSetDefaultCommConfig, dwRet);
|
|
|
|
return dwRet;
|
|
}
|