c++cwinapisizeras

RAS API. sizeof(RASDIALPARAMS) is wrong. Error 632


I'm working with RAS API under Windows 7 x32. The following function returns error 632 (ERROR_INVALID_SIZE):

int32_t set_username_passwd(wchar_t *entry_title)
{
    RASDIALPARAMS ras_param;
    ZeroMemory(&ras_param, sizeof(RASDIALPARAMS));
    ras_param.dwSize = sizeof(RASDIALPARAMS);
    memcpy(ras_param.szEntryName, entry_title, wcslen(entry_title));
    memcpy(ras_param.szUserName, L"username", wcslen(L"username"));
    memcpy(ras_param.szPassword, L"password", wcslen(L"password"));
    return RasSetEntryDialParams(0, &ras_param, 0);
}

sizeof(RASDIALPARAMS) returns wrong size? How could it be?

Or what am i missing?


Solution

  • RASDIALPARAMS has had new fields added to it over the years:

    #define RASDIALPARAMSW struct tagRASDIALPARAMSW
    RASDIALPARAMSW
    {
        DWORD dwSize;
        WCHAR szEntryName[ RAS_MaxEntryName + 1 ];
        WCHAR szPhoneNumber[ RAS_MaxPhoneNumber + 1 ];
        WCHAR szCallbackNumber[ RAS_MaxCallbackNumber + 1 ];
        WCHAR szUserName[ UNLEN + 1 ];
        WCHAR szPassword[ PWLEN + 1 ];
        WCHAR szDomain[ DNLEN + 1 ];
    #if (WINVER >= 0x401) // 95/NT4 and later
        DWORD dwSubEntry;
        ULONG_PTR dwCallbackId;
    #endif
    #if (WINVER >= 0x601) // Windows 7 and later
        DWORD dwIfIndex;
    #endif
    };
    

    As such, the size of RASDIALPARAMS that RasSetEntryDialParams() expects depends on the particular Windows version. But the actual size of RASDIALPARAMS inside of your app depends on the WINVER define during compiling, as seen above.

    So, when targeting Windows 7, WINVER must be set to a value that is at least 0x601 (Windows 7 is v6.1). If you compile with a lower WINVER value then the size of RASDIALPARAMS will be too small for Windows 7 to accept.

    If you set WINVER to a higher value than the Windows version that you are targeting, you can detect the OS version at runtime and set ras_param.dwSize to the appropriate size since sizeof(RASDIALPARAMS) will be larger than what RasSetEntryDialParams() is expecting. For example:

    int32_t set_username_passwd(wchar_t *entry_title)
    {
        RASDIALPARAMSW ras_param;
        ZeroMemory(&ras_param, sizeof(ras_param));
    
        OSVERSIONINFO osvi;
        ZeroMemory(&osvi, sizeof(osvi));
    
        GetVersionEx(&osvi);
    
        #if (WINVER >= 0x401)
        if ((osvi.dwMajorVersion < 4) ||
           ((osvi.dwMajorVersion == 4) && (osvi.dwMinVersion < 1)) )
        {
            ras_param.dwSize = offsetof(RASDIALPARAMSW, dwSubEntry);
        }
        else
        #endif
        #if (WINVER >= 0x601)
        if ((osvi.dwMajorVersion < 6) ||
           ((osvi.dwMajorVersion == 6) && (osvi.dwMinVersion < 1)) )
        {
            ras_param.dwSize = offsetof(RASDIALPARAMSW, dwIfIndex);
        }
        else
        #endif
        {
            ras_param.dwSize = sizeof(ras_param);
        }
    
        wcsncpy(ras_param.szEntryName, entry_title, RAS_MaxEntryName);
        wcsncpy(ras_param.szUserName, L"username", UNLEN);
        wcsncpy(ras_param.szPassword, L"password", PWLEN);
    
        return RasSetEntryDialParamsW(0, &ras_param, 0);
    }
    

    Alternatively, you can skip the OS check and just handle the ERROR_INVALID_SIZE error instead:

    int32_t set_username_passwd(wchar_t *entry_title)
    {
        RASDIALPARAMSW ras_param;
        ZeroMemory(&ras_param, sizeof(ras_param));
    
        ras_param.dwSize = sizeof(ras_param);
        wcsncpy(ras_param.szEntryName, entry_title, RAS_MaxEntryName);
        wcsncpy(ras_param.szUserName, L"username", UNLEN);
        wcsncpy(ras_param.szPassword, L"password", PWLEN);
    
        DWORD dwRet = RasSetEntryDialParamsW(0, &ras_param, 0);
        #if (WINVER >= 0x601)
        if (dwRet == ERROR_INVALID_SIZE)
        {
            ras_param.dwSize = offsetof(RASDIALPARAMSW, dwIfIndex);
            dwRet = RasSetEntryDialParamsW(0, &ras_param, 0);
        }
        #elif (WINVER >= 0x401)
        if (dwRet == ERROR_INVALID_SIZE)
        {
            ras_param.dwSize = offsetof(RASDIALPARAMSW, dwSubEntry);
            dwRet = RasSetEntryDialParamsW(0, &ras_param, 0);
        }
        #endif
    
        return dwRet;
    }