在Win32 API 函数中有一组用于实现远程连接服务RAS 的函数,利用这些函数通过编程可以实现建立和Internet 的拨号连接,并可获得Internet 分配给主机的动态IP 地址。
一、建立拨号连接API
建立拨号连接是利用函数RasDial() 实现的,该函数调用后立即返回,若成功返回0 值,否则返回非0 值。在拨号连接过程中,回调函数接收连接的状态信息及发生的错误代码。回调函数的原形如下:VOID WINAPI RasDialFunc(UINT unMsg,RASCONNSTATE rasconnstate,DWORD dwError)
由于在调用RasDialFunc 函数时,连接操作被挂起,因此,应用程序应尽快处理发生的事件并返回。可以在RasDialFunc 函数中调用PostMessage 函数,将事件通知消息送给窗口函数来处理。
RASDIALPARAMS 结构定义如下:
DWORD dwSize 结构变量的大小。
TCHAR szEntryName[RAS_MaxEntryName +1] 拨号网络中建立的连接名。
TCHAR szPhoneNumber[RAS_MaxPhoneNumber +1] 电话号码,若采用szEntryName 中定义的号码,置为NULL 值。
TCHAR szCallbackNumber[RAS_MaxCallbackNumber +1] 回拨号码,不用时置为NULL。
TCHAR szUserName[UNLEN +1] 用户标识。
TCHAR szPassword[PWLEN +1] 用户口令。
TCHAR szDomain[DNLEN +1] 用户权限验证域,若为NULL 采用RAS 服务器所在的域进行验证,若为‘*’采用szEntryName 中定义的域进行验证。
RASCONNSTATE 枚举型结构,包含拨号连接过程中各种可能状态的定义。
函数RasHangUp() 用来终止拨号连接,因程序需要一定的时间来结束连接,应用程序调用该函数后不能马上退出,需等待3 秒后才能退出。
二、获取动态IP 地址API
在VC 中是通过调用函数RasGetProjectionInfo() 来获取IP 地址的。
函数调用成功时返回0 值,此时在RASPPPIP 结构变量中的szIpAddress 就是动态IP 地址。
三、程序实现
程序是在Win 95 环境下,用VC ++5.0 编写,并编译运行通过。完整的源程序清单如下:
// --- -------------
//file name ras.c
// --- -------------
#include < windows.h >
#include < winuser.h >
#include < string.h >
#include < ras.h >
#include < raserror.h >
#include "resource.h"
// 函数原形
LRESULT CALLBACK DialogProc(HWND hDlg,
UINT message, WPARAM wParam, LPARAM lParam);
void ShowMsg(HWND hwnd,char *msg);
LRESULT MsgDialDlgEvent(HWND hdlg,
UINT uMessage, WPARAM wparam, LPARAM lparam);
VOID WINAPI RasDialFunc
( UINT unMsg, RASCONNSTATE rasconnstate,
DWORD dwError );
BOOL StartCon( HWND hWnd,char
*szUser,char *szPassword );
UINT GetRasConnState( RASCONNSTATE rasconn );
// 全局变量
HRASCONN hCon; //RAS 连接句柄
HWND hWin;
HINSTANCE hInst;
// --- --------------
//windows 入口函数
// --- --------------
int PASCAL WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,LPSTR lpszCmdLine,
int nCmdShow )
{
hInst=hInstance;
if ( DialogBox(hInstance,"RAS_DLG",NULL,
(DLGPROC)DialogProc) == -1 )
MessageBox(NULL,"建立对话框失败!",
"TITLE",MB_OK);
return 0;
}
// -----------------
// 对话框窗口函数
// -----------------
LRESULT CALLBACK DialogProc(HWND hDlg,
UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
hWin=hDlg;
hCon=NULL;
return (TRUE);
case WM_RASDIALEVENT:
MsgDialDlgEvent(hDlg,message,wParam,lParam);
return (TRUE);
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
StartCon( hDlg,"ljx@public.smptt.fj.cn",
"abbcd");
break;
case IDCANCEL:
if ( hCon != NULL )
{
RasHangUp(hCon);
Sleep(3000);
}
EndDialog(hDlg,TRUE);
break;
}
break;
}
return (FALSE);
}
// ****************
// 在列表框中显示信息
// ****************
void ShowMsg(HWND hwnd,char *msg)
{
int lnum;
SendDlgItemMessage(hwnd,IDC_MSG,
LB_ADD ?STRING,0,(long)msg );
lnum=SendDlgItemMessage(hwnd,IDC_MSG,
LB_GETCOUNT, 0,0);
SendDlgItemMessage(hwnd,IDC_MSG,LB_SET ?
CURSEL,lnum -1,0);
return;
}
// -----------------
// BOOL StartCon( HWND hWnd )
// 建立拨号连接, 成功TRUE else FALSE
// szUser 和szPassword 分别为
Internet 的用户名和口令
// -----------------
BOOL StartCon
( HWND hWnd,char *szUser,char *szPassword )
{
RASDIALPARAMS rdParams;
DWORD dwRet;
char szBuf[300];
// 初始化变量
rdParams.dwSize = sizeof(RASDIALPARAMS);
lstrcpy(rdParams.szEntryName, "internet");
rdParams.szPhoneNumber[0] = '\0';
rdParams.szCallbackNumber[0] = '*';
rdParams.szCallbackNumber[0] = '\0';
strcpy(rdParams.szUserName,szUser);
strcpy(rdParams.szPassword,szPassword);
rdParams.szDomain[0] = '\0';
hCon=NULL;
// 以下开始异步拨叫网络
dwRet = RasDial( NULL, NULL, &rdParams, 0L,
(RASDIALFUNC) RasDialFunc, &hCon );
if ( dwRet )
{
if ( RasGetErrorString( (UINT)dwRet,
(LPSTR)szBuf, 256 ) != 0 )
wsprintf( (LPSTR)szBuf,
“Undefined RAS Dial Error ( %ld).", dwRet );
ShowMsg(hWnd,szBuf);
return FALSE;
}
return TRUE;
}
// ---------------
// RasDial 异步处理的回调函数
// unMsg -发生的RAS 事件
// rasconnstate -连接进入的状态
// dwError -发生的错误代码
// ---------------
VOID WINAPI RasDialFunc
( UINT unMsg, RASCONNSTATE rasconnstate,
DWORD dwError )
{
PostMessage(hWin,
WM_RASDIALEVENT,
(WPARAM) rasconnstate,
(LPARAM) dwError );
}
// ----------------
// RasDial() 返回的事件信息由该函数处理
// ----------------
LRESULT MsgDialDlgEvent(HWND hdlg, UINT uMessage,
WPARAM wparam, LPARAM lparam)
{
RASPPPIP rip;
DWORD ll,ret;
int num;
char szMessage[256];
LoadString(hInst,GetRasConnState
( (RASCONNSTATE) wparam ), szMessage, 64 );
ShowMsg(hdlg,szMessage);
if ( lparam ) // 发生错误
{
if ( RasGetErrorString
( (UINT)lparam, szMessage, 256 ) != 0 )
wsprintf( (LPSTR)szMessage,
“出错Undefined RAS Dial Error." );
ShowMsg(hdlg,szMessage);
return TRUE;
}
else if ( RASCS_DONE &wparam ) // 连接成功
{
// 取动态分配的IP 地址
ShowMsg(hdlg,"连接成功");
rip.dwSize=sizeof(RASPPPIP);
if((ret=RasGetProjectionInfo(hCon,RASP_PppIp,
(LPVOID) &rip,(LPDWORD) &ll )) != 0 )
{
ShowMsg(hdlg,"取IP 地址失败");
}
else
ShowMsg(hdlg,rip.szIpAddress);
}
return TRUE;
}
// ----------------
// 根据连接状态
取字符串资源中对应的标号
// ----------------
UINT GetRasConnState( RASCONNSTATE rasconn )
{
switch( rasconn )
{
case RASCS_OpenPort:
return IDS_OPENPORT;
case RASCS_PortOpened:
return IDS_PORTOPENED;
case RASCS_ConnectDevice:
return IDS_CONNECTDEVICE;
case RASCS_DeviceConnected:
return IDS_DEVICECONNECTED;
case RASCS_AllDevicesConnected:
return IDS_ALLDEVICESCONNECTED;
case RASCS_Authenticate:
return IDS_AUTHENTICATE;
case RASCS_AuthNotify:
return IDS_AUTHNOTIFY;
case RASCS_AuthRetry:
return IDS_AUTHRETRY;
case RASCS_AuthCallback:
return IDS_AUTHCALLBACK;
case RASCS_AuthChangePassword:
return IDS_AUTHCHANGEPASSWORD;
case RASCS_AuthProject:
return IDS_AUTHPROJECT;
case RASCS_AuthLinkSpeed:
return IDS_AUTHLINKSPEED;
case RASCS_AuthAck:
return IDS_AUTHACK;
case RASCS_ReAuthenticate:
return IDS_REAUTHENTICATE;
case RASCS_Authenticated:
return IDS_AUTHENTICATED;
case RASCS_PrepareForCallback:
return IDS_PREPAREFORCALLBACK;
case RASCS_WaitForModemReset:
return IDS_WAITFORMODEMRESET;
case RASCS_WaitForCallback:
return IDS_WAITFORCALLBACK;
case RASCS_Interactive:
return IDS_INTERACTIVE;
case RASCS_RetryAuthentication:
return IDS_RETRYAUTHENTICATION;
case RASCS_CallbackSetByCaller:
return IDS_CALLBACKSETBYCALLER;
case RASCS_PasswordExpired:
return IDS_PASSWORDEXPIRED;
case RASCS_Connected:
return IDS_CONNECTED;
case RASCS_Disconnected:
return IDS_DISCONNECTED;
default:
return IDS_UNDEFINED_ERROR;
}
}
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
华丽的分割线---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
序:近日,有位朋友问到用VC实现拨号上网的程序,今天在网上无意中发现了这篇文章,于是便转载过来,希望对这位朋友有所帮助!
正文:
大家知道,在netants、download expert等软件中都带有定时拨号上网下载软件的功能。而一般用户的拨号上网,利用的是windows的remote access service(ras,远程访问服务)。下面介绍一下其在visual c++下的实现。
visual c++为我们提供了包含ras api声明的“ras.h″头文件。要在程序中实现拨号上网功能,其大致过程如下:
1. 利用modem拨号进行连接,应使用rasdial函数。
其声明如下:
dword ras dial(lprasdialextensions lpras dialextensions,lpctstr lpszphonebook,lprasdialparams lp ras dialparams,dword dw notifier type,lpvoid lpv notifier, lphrasconn lph ras conn )
参数说明:
lprasdialextensions和lpszphonebook:仅在windows nt下有效,在windows 95下,这两个参数被忽略。
lprasdialparams:这个参数很重要,它指向一个rasdialparams结构,该结构包含以下几个成员:
dwsize:应设定为sizeof(rasdialparams);
szentryname和szphonenumber:这两个参数有联系,szentryname可以指定要建立的连接,比方说“我的连接”等等,这是处理用户已经在“拨号网络”里建立的连接的。这时,modem将拨打你在“我的连接”中设定的isp号码,此时szphonenumber成员设为空字符串“”即可;如果你要在程序中自行指定要拨打的isp号码的话,szentryname可以设定为空字符串“”,此时应设置szphonenumber为你的isp号码(169,663等),特别的,对于用201电话卡来上网的情况,可以设为“201,,,账号,密码#,,isp号码#”(其中“,”表示停顿一段时间(以等待确认账号,密码等),你可以根据自己所在位置的线路状况自行调节。 szcallbacknumber,szdomain:设为空串“”即可。 szusername,szpassword:登录用户名和密码。如169公用账号guest,guest。
其他成员不必设置。
dwnotifiertype:指定是由窗口还是由回调函数来处理确认消息。通过确认消息我们可以得到rasdial过程的当前状态。如“正在打开段口”,“正在验证用户名和密码”等。也可设为null。 dwnotifier:指定处理确认消息的窗口或回调函数。也可设为null。
lphrasconn:指向一个类型为hrasconn的变量。在调用rasdial前必须指定为null,rasdial若成功返回,则将ras连接的句柄存放于它所指向的变量中。我们也可以通过此句柄来断开连接。
只要在程序中适当位置调用rasdial函数即可建立连接。
2. 理确认消息以得到拨号过程的当前状态。
我们以指定窗口来处理确认消息为例说明如何得到拨号过程的当前状态。
在处理确认消息的对话框类(或视图类等)的实现代码中加入:
const uint wm_rasevent = ::registerwindowmessagea(rasdialevent);
在message map中手工加入消息映射:(****是你定义的对话框类名称)
begin_message_map(****, cdialog)
file://afx_msg_map(****)
……
on_registered_message(wm_rasevent, onrasdialevent)(<-加入此句)
file://afx_msg_map
end_message_map()
加入成员函数处理消息:
lresult cdialinfo::onrasdialevent(wparam wp, lparam lp)
{
rasconnstate rasstate= (rasconnstate)wp;
clistbox *info =(clistbox *)getdlgitem(idc_infolist);
file://用listbox 控件(id为idc-infolist)来显示状态)
switch(rasstate)
{
case rascs_openport:
info→addstring(_t(″打开端口……″));
break;
case rascs_portopened:
info→addstring(_t(″端口已打开.″));
break;
case rascs_connectdevice:
info→addstring(_t(″连接设备……″));
break;
case rascs_deviceconnected:
info→addstring(_t(″设备已连接.″));
break;
case rascs_authenticate:
info→addstring(_t(″验证用户及密码″));
break;
case rascs_authenticated:
info→addstring(_t(″通过″));
break;
case rascs_connected:
info->addstring(_t(″已连接″));
reak;
case rascs_disconnected:
info->addstring(_t(″连接已断开″));
m_hrasconn=null;
file://可定义类型为hrasconn的成员变量m_hrasconn来保存ras连接的句柄。
file://在调用rasdial时用指向m_hrasconn的指针作为lphrasconn参数。
file://既然用m_hrasconn来保存连接句柄,连接断开后应重置为null.
break;
default:
return (lresult)0;
}
return (lresult)0;
}
3. 断开连接:
if (m_hrasconn != null)
{
rashangup(m_hrasconn);
m_hrasconn = null;
m_ondial=true;
:sleep(2000);
}
注意 :
你也许注意到了以上代码中的sleep函数,这里是必需的。需要一定时间来断开连接。如果不等待一段时间,计算机有可能无法正常关闭端口。导致下一次无法拨号,只有重新启动windows才能解决。要预防此问题也可以调用rasgetconnectstatus函数,方法如下:
rasconnstatus rstatus;
while(rasgetconnectstatus(m_hrasconn,&rstatus)!=error_invalid_handle)
{
::sleep(0);
}
4.在以下情况下:
① 浏览网页时有时会出现停止响应,重启explorer后任务栏上的连接状态图标也许会消失。
② 希望在连接成功后,退出程序,再次执行此程序可选择断开连接。
可以调用rasenumconnection函数来得到当前连接的句柄。
举例如下:
hrasconn hrasconnect;dword dwbufffersize, dwnumofconnections;//缓冲区大小,连接数
lprasconn lprasconn;
lprasconn = new rasconn[3】;//最多可得到3个连接句柄,客户端程序其实不必设为3,因连接数有限,大部分仅一个连接。
lprasconn[0】.dwsize = sizeof(rasconn);
dwbufffersize = 32* sizeof(rasconn);//求出由3个rasconn结构构成的缓冲区大小
rasenumconnections(lpras conn, &dw buffer size, &dw numof connections);//此函数若成功则返回零。
for(dword i=0; i {
hrasconnect = lprasconn[i】.hrasconn;//rasconn结构的hrasconn成员为ras连接句柄
rashangup(hrasconnect);
::sleep(2000);
}
delete [】 lprasconn;
在windows 98,visual c++ 6.0下调试通过。
这样,一个实现基本拨号上网功能的程序就完成了。如果你要了解更多有关情况或服务器端程序设计,可以参考msdn→platform sdk→networking and distributed services→remote access service的有关内容
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
华丽的分割线---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
背景:代替手工自动进行PPPOE拨号
相关知识:
主要使用的函数:
The RasDial function establishes a RAS connection between a RAS client and a RAS server. The connection data includes callback and user-authentication information
DWORD RasDial(
__in LPRASDIALEXTENSIONS lpRasDialExtensions,
__in LPCTSTR lpszPhonebook,
__in LPRASDIALPARAMS lpRasDialParams,
__in DWORD dwNotifierType,
__in LPVOID lpvNotifier,
__in LPHRASCONN lphRasConn
);
Return Value
If the function succeeds, the return value is ERROR_SUCCESS and a handle to the RAS connection is returned in the variable pointed to by lphRasConn .
If the function fails, the return value is from Routing and Remote Access Error Codes or Winerror.h.
更多消息请查看 :
http://msdn.microsoft.com/en-us/library/aa377004(VS.85).aspx
RASDIALPARAMS ms;
RASDIALPARAMS params;
HRASCONN handle=NULL;
memset(&ms, '/0', sizeof(params));
params.dwSize=sizeof(RASDIALPARAMS);
CString entryname;
CString tmp;
tmp.Format("%d", i);
entryname="UE"+tmp;//需要拨号的名称,也就是建立的宽带连接的名称,如UE0
strcpy(params.szEntryName,entryname);
strcpy(params.szPhoneNumber,"");
strcpy(params.szCallbackNumber,"");
strcpy(params.szUserName,"tm500"); //用户名
strcpy(params.szPassword, "tm500"); //密码
strcpy(params.szDomain, "");
Message +="/n"+entryname+"dailying up ......";
UpdateData(TRUE);
//指定的拨号连接。
int a =RasDial(NULL, NULL, ¶ms, NULL, NULL, &handle);
if (a!=ERROR_SUCCESS)
{
MessageBox("正在拨打的计算机没有应答,稍后请再试");
Message +="/n"+entryname+"dailying up failed....../n";
UpdateData(TRUE);
DWORD off=RasHangUp(handle);
//SendMessage(WM_CLOSE);
if (off==0)
{
MessageBox("连接已断开");
//printf("连接已断开.../n");
}
else{
//printf("断开连接出错.../n");
MessageBox("断开连接出错.");
}
}
C++ 拨号函数演示 -
-
-
-
-
-
-
-
-
- #include <windows.h>
- #include <stdio.h>
- #include <Ras.h>
- #pragma comment(lib,"rasapi32.lib")
-
- int main(int argc,char *argv[])
- {
- printf("UserName:");
- char user[100]={0};
- scanf("%s",user);
- printf("PassWord:");
- char pass[100]={0};
- scanf("%s",pass);
-
-
-
- RASDIALPARAMSA rdParams;
- rdParams.dwSize=sizeof(RASDIALPARAMSA);
- strcpy(rdParams.szEntryName,"宽带连接");
- rdParams.szPhoneNumber[0]='\0';
- rdParams.szCallbackNumber[0]='\0';
- strcpy(rdParams.szUserName,user);
- strcpy(rdParams.szPassword,pass);
- rdParams.szDomain[0]='\0';
- HRASCONN hRscon=NULL;
- DWORD retn= RasDialA(NULL,NULL,&rdParams,0L,NULL,&hRscon);
-
- if (retn==0)
- {
- printf("已经连接上...\n");
-
-
-
-
-
-
-
-
-
-
- return 0;
- }
- printf("连接出错...\n");
- return 0;
|
posted on 2013-03-17 19:51
聂文龙 阅读(5477)
评论(0) 编辑 收藏 引用 所属分类:
Visual C++