Editing the Device Configuration

Unimodem now supports a programmatic mechanism for editing the device configuration. Previously, the only way to edit a Unimodem device configuration block was by using the lineConfigDialogEdit function that requires user interaction. Now you can edit a Unimodem device configuration by using the lineDevSpecific function extensions, which require no user interaction. The details of this interface are defined in Unimodem.h.

The following sample application demonstrates how to use this interface.

//
// Program to demonstrate and test the lineDevSpecific interface to 
// Unimodem for setting a device
// configuration without calling lineConfigDialogEdit.
//

#include <Windows.h>
#include <Windowsx.h>
#include <Tapi.h>
#include <Tapidbg.h>
#include <Mcx.h>
#include <Unimodem.h>
#include <Netui.h>

HLINEAPP g_hLineApp;
HLINE g_hLine;
DWORD g_dwNumLines;
DWORD g_dwAPIVersion;
DWORD g_dwExtVersion;
LONG  rc;

LINEMESSAGE LineMessage;

DWORD g_NextOp;
LPVARSTRING g_DevCfg;
WCHAR g_Str[256];
LPWSTR g_DevClass = TEXT("comm/datamodem");
UNIMDM_CHG_DEVCFG g_UCD;

typedef struct _OPTABLEENTRY {
    DWORD dwOption;
    DWORD dwValue;
} OPTABLEENTRY, *POPTABLEENTRY;

/*  from Unimodem.h
#define UNIMDM_OPT_BAUDRATE     1 // Use CBR_* values from Winbase.h.
#define UNIMDM_OPT_BYTESIZE     2
#define UNIMDM_OPT_PARITY       3 // Use values from Winbase.h.
#define UNIMDM_OPT_STOPBITS     4 // Use values from Winbase.h.
#define UNIMDM_OPT_WAITBONG     5 // Seconds to wait for prompt tone.
#define UNIMDM_OPT_MDMOPTIONS   6 // Use MDM_* values from Mcx.h.
#define UNIMDM_OPT_TIMEOUT      7 // Call setup fail timer in seconds.
#define UNIMDM_OPT_TERMOPTIONS  8 // Use NETUI_LCD_TRMOPT_* values from Netui.h.
#define UNIMDM_OPT_DIALMOD      9 // Dial modifier (dwValue is a LPCWSTR).
*/

OPTABLEENTRY g_OpTable[] = {
    UNIMDM_OPT_BAUDRATE,    CBR_57600,
    UNIMDM_OPT_BAUDRATE,    987654,

    UNIMDM_OPT_BYTESIZE,    5,
    UNIMDM_OPT_BYTESIZE,    6,
    UNIMDM_OPT_BYTESIZE,    7,
    UNIMDM_OPT_BYTESIZE,    8,
    UNIMDM_OPT_BYTESIZE,    9,
    UNIMDM_OPT_BYTESIZE,    10,
    UNIMDM_OPT_BYTESIZE,    11,
    UNIMDM_OPT_BYTESIZE,    16,

    UNIMDM_OPT_PARITY,      NOPARITY,
    UNIMDM_OPT_PARITY,      ODDPARITY,
    UNIMDM_OPT_PARITY,      EVENPARITY,
    UNIMDM_OPT_PARITY,      MARKPARITY,
    UNIMDM_OPT_PARITY,      SPACEPARITY,
    UNIMDM_OPT_PARITY,      5,
    UNIMDM_OPT_PARITY,      55,

    UNIMDM_OPT_STOPBITS,    ONESTOPBIT,
    UNIMDM_OPT_STOPBITS,    ONE5STOPBITS,
    UNIMDM_OPT_STOPBITS,    TWOSTOPBITS,
    UNIMDM_OPT_STOPBITS,    3,
    UNIMDM_OPT_STOPBITS,    33,

    UNIMDM_OPT_WAITBONG,    111,
    UNIMDM_OPT_TIMEOUT,     222,

    UNIMDM_OPT_TERMOPTIONS, 0,
    UNIMDM_OPT_TERMOPTIONS, NETUI_LCD_TRMOPT_MANUAL_DIAL,
    UNIMDM_OPT_TERMOPTIONS, NETUI_LCD_TRMOPT_PRE_DIAL,
    UNIMDM_OPT_TERMOPTIONS, NETUI_LCD_TRMOPT_POST_DIAL,

    UNIMDM_OPT_DIALMOD,     (DWORD)TEXT("ABCDEFG"),
    UNIMDM_OPT_DIALMOD,     (DWORD)TEXT("1234567890,abdfgei,ABCDEFG"),

};

void
GetStringNames(
    LPWSTR * ppszOptionName,
    LPWSTR * ppszValueName
    )
{
    LPWSTR tmp;

    *ppszValueName = NULL;
    tmp = g_Str;
    *tmp = 0;

    switch (g_OpTable[g_NextOp].dwOption) {
    case UNIMDM_OPT_BAUDRATE:
        *ppszOptionName = TEXT("Baud Rate");
        break;

    case UNIMDM_OPT_BYTESIZE:
        *ppszOptionName = TEXT("Byte Size");
        break;

    case UNIMDM_OPT_PARITY:
        *ppszOptionName = TEXT("Parity");
        switch (g_OpTable[g_NextOp].dwValue) {
        case NOPARITY:      *ppszValueName = TEXT("None"); break;
        case ODDPARITY:     *ppszValueName = TEXT("Odd"); break;
        case EVENPARITY:    *ppszValueName = TEXT("None"); break;
        case MARKPARITY:    *ppszValueName = TEXT("Mark"); break;
        case SPACEPARITY:   *ppszValueName = TEXT("Space"); break;
        }
        break;

    case UNIMDM_OPT_STOPBITS:
        *ppszOptionName = TEXT("Stop Bits");
        switch (g_OpTable[g_NextOp].dwValue) {
        case ONESTOPBIT:    *ppszValueName = TEXT("1"); break;
        case ONE5STOPBITS:  *ppszValueName = TEXT("1.5"); break;
        }
        break;

    case UNIMDM_OPT_WAITBONG:
        *ppszOptionName = TEXT("Wait Bong");
        break;

    case UNIMDM_OPT_MDMOPTIONS:
        *ppszOptionName = TEXT("Modem Options");
        break;

    case UNIMDM_OPT_TIMEOUT:
        *ppszOptionName = TEXT("Fail Time-out");
        break;

    case UNIMDM_OPT_TERMOPTIONS:
        *ppszOptionName = TEXT("Terminal Options");
        if (g_OpTable[g_NextOp].dwValue & NETUI_LCD_TRMOPT_MANUAL_DIAL) {
            wcscat(tmp, TEXT("Manual Dial "));
        }
        if (g_OpTable[g_NextOp].dwValue & NETUI_LCD_TRMOPT_PRE_DIAL) {
            wcscat(tmp, TEXT("Pre-dial Terminal "));
        }
        if (g_OpTable[g_NextOp].dwValue & NETUI_LCD_TRMOPT_POST_DIAL) {
            wcscat(tmp, TEXT("Post-dial Terminal "));
        }
        if (*tmp) {
            *ppszValueName = tmp;
        }
        break;

    case UNIMDM_OPT_DIALMOD:
        *ppszOptionName = TEXT("Dial Modifier");
        *ppszValueName = (LPWSTR)g_OpTable[g_NextOp].dwValue;
        break;

    default:
        *ppszOptionName = TEXT("Unknown Option");
        break;
    }
}   // GetStringNames

LONG DoNextOperation(void)
{
    LPWSTR lpszOptionName;
    LPWSTR lpszValueName;

    g_UCD.dwCommand = UNIMDM_CMD_CHG_DEVCFG;
    g_UCD.lpszDeviceClass = g_DevClass;
    g_UCD.lpDevConfig = g_DevCfg;

    g_UCD.dwOption = g_OpTable[g_NextOp].dwOption;
    g_UCD.dwValue  = g_OpTable[g_NextOp].dwValue;

    GetStringNames(&lpszOptionName, &lpszValueName);
    if (lpszValueName) {
        NKDbgPrintfW(TEXT("DEVCFG %d: Changing %s to %s\n"), g_NextOp, lpszOptionName, lpszValueName);
    } else {
        NKDbgPrintfW(TEXT("DEVCFG %d: Changing %s to %d\n"), g_NextOp, lpszOptionName, g_UCD.dwValue);
    }

    rc = lineDevSpecific(
            g_hLine,
            0,
            NULL,
            &g_UCD,
            sizeof(g_UCD)
            );

    NKDbgPrintfW(TEXT("DEVCFG lineDevSpecific(%d) returned %s\n"), g_NextOp, TAPIErrorName(rc));
    g_NextOp++;
    return rc;
}   // DoNextOperation


void WaitForReply(void)
{
    lineGetMessage(
        g_hLineApp,
        &LineMessage,
        INFINITE
        );
    
    if (LineMessage.dwMessageID == LINE_REPLY) {
        NKDbgPrintfW(TEXT("DEVCFG: Got LINE_REPLY %s\n"), TAPIErrorName(LineMessage.dwParam2));
    }
}


//
// Find a device ID from a specific service provider.
//
// Relies on globals:
//  HLINEAPP g_hLineApp;
//  DWORD g_dwNumLines;
//  DWORD g_dwAPIVersion;
//  DWORD g_dwExtVersion;
// 
DWORD
FindTSPDevice(
    DWORD TSP
    )
{

    DWORD dwDeviceID;
    LPWSTR lpszProviderInfo;
    BYTE buf[1024];
    LPLINEDEVCAPS lpDevCaps;
    LPWSTR lpszTSPName;
    DWORD rc;

    lpszTSPName = L"UNIMODEM";
    lpDevCaps = (LPLINEDEVCAPS)buf;
    lpDevCaps->dwTotalSize = sizeof(buf);

    for (dwDeviceID = 0; dwDeviceID < g_dwNumLines; dwDeviceID++) {
        rc = lineGetDevCaps(
                g_hLineApp,
                dwDeviceID,
                g_dwAPIVersion,
                g_dwExtVersion,
                lpDevCaps
                );
        if (rc) {
            NKDbgPrintfW(TEXT("FindTSPDevice lineGetDevCaps(%d) returned 0x%x\n"), dwDeviceID, rc);
            continue;
        }
        lpszProviderInfo = (LPWSTR)((DWORD)lpDevCaps + lpDevCaps->dwProviderInfoOffset);
        if (!(wcsicmp(lpszProviderInfo, lpszTSPName))) {
            return dwDeviceID;
        }
    }
    return 0xffffffff;
}   // FindTSPDevice.

//
// Get the default DevConfig and its size.
//
BOOL GetDevConfig(DWORD dwDeviceID)
{
    DWORD dwLen;
    //
    // Find out how big its DevConfig is, and get it.
    //
    dwLen = sizeof(VARSTRING);
    g_DevCfg = LocalAlloc(LPTR, dwLen);
    if (NULL == g_DevCfg) {
        goto gdc_fail;
    }

    g_DevCfg->dwTotalSize = dwLen;
    rc = lineGetDevConfig(
            dwDeviceID,
            g_DevCfg,
            TEXT("comm/datamodem")
            );
    if (rc) {
        goto gdc_fail;
    }

    if (g_DevCfg->dwTotalSize < g_DevCfg->dwNeededSize) {
        dwLen = g_DevCfg->dwNeededSize;
        LocalFree(g_DevCfg);
        g_DevCfg = LocalAlloc(LPTR, dwLen);
        if (NULL == g_DevCfg) {
            goto gdc_fail;
        }

        g_DevCfg->dwTotalSize = dwLen;
        rc = lineGetDevConfig(
                dwDeviceID,
                g_DevCfg,
                TEXT("comm/datamodem")
                );
        if (rc) {
            goto gdc_fail;
        }
    }
    return TRUE;

gdc_fail:
    return FALSE;
}   // GetDevConfig


int
WINAPI
WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPWSTR lpCmdLine,
    int nCmdShow
    )
{
    DWORD dwDeviceID;
    LPVARSTRING vs;

    LINEINITIALIZEEXPARAMS    LineInitializeExParams = {
        sizeof(LINEINITIALIZEEXPARAMS),    //dwTotalSize
        0,                                 //dwNeededSize
        0,                                 //dwUsedSize
        LINEINITIALIZEEXOPTION_USEEVENT,   //dwOptions
        0,                                 //Handles
        0                                  //dwCompletionKey
    };
    
    g_dwAPIVersion = TAPI_CURRENT_VERSION;
    g_dwExtVersion = 0;
       
    rc = lineInitializeEx(
            &g_hLineApp,
            hInstance,
            NULL,
            TEXT("DEVCFG"),
            &g_dwNumLines,
            &g_dwAPIVersion,
            &LineInitializeExParams
            );
    
    if (rc) {
        NKDbgPrintfW(TEXT("DEVCFG: lineInitializeEx failed %s\n"), TAPIErrorName(rc));
        rc = 1;
        goto main_exit;
    }
    
    dwDeviceID = FindTSPDevice(1);

    rc = lineOpen(
            g_hLineApp,                    //g_hLineApp
            dwDeviceID,                    //dwDeviceID
            &g_hLine,                      //lphLine
            g_dwAPIVersion,
            g_dwExtVersion,
            0,                             //dwCallbackInstance
            LINECALLPRIVILEGE_OWNER,       //dwPrivileges
            LINEMEDIAMODE_DATAMODEM,       //dwMediaModes
            NULL                           //lpCallParams
            );                
    
    if (rc) {
        NKDbgPrintfW(TEXT("DEVCFG: lineOpen failed %s\n"), TAPIErrorName(rc));
        goto main_exit;
    }


    if (!GetDevConfig(dwDeviceID)) {
        NKDbgPrintfW(TEXT("DEVCFG: GetDevConfig\n"));
        goto main_exit;
    }

    g_NextOp = 0;
    while (g_NextOp < sizeof(g_OpTable)/sizeof(OPTABLEENTRY)) {
        if (!(DoNextOperation() & 0x80000000)) {
            WaitForReply();
        }
    }


    //
    // Call lineConfigDialogEdit to verify changes.
    //
    vs = (LPVARSTRING)g_Str; // Reuse string buffer.
    vs->dwTotalSize = sizeof(g_Str);

    lineConfigDialogEdit(
        dwDeviceID,
        NULL,
        g_DevClass,
        (LPVOID)((LPBYTE)g_DevCfg + sizeof(VARSTRING)),
        g_DevCfg->dwUsedSize - sizeof(VARSTRING),
        vs
        );
    
main_exit:
    NKDbgPrintfW(TEXT("DEVCFG: calling lineShutdown\n"));
    lineShutdown(g_hLineApp);
    NKDbgPrintfW(TEXT("DEVCFG: exiting\n"));    
    return rc;
}

See Also

Unimodem Support

 Last updated on Friday, April 09, 2004

© 1992-2003 Microsoft Corporation. All rights reserved.