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?
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;
}