在Win32 API 函數(shù)中有一組用于實(shí)現(xiàn)遠(yuǎn)程連接服務(wù)RAS 的函數(shù),利用這些函數(shù)通過編程可以實(shí)現(xiàn)建立和Internet 的撥號(hào)連接,并可獲得Internet 分配給主機(jī)的動(dòng)態(tài)IP 地址。
一、建立撥號(hào)連接API
建立撥號(hào)連接是利用函數(shù)RasDial() 實(shí)現(xiàn)的,該函數(shù)調(diào)用后立即返回,若成功返回0 值,否則返回非0 值。在撥號(hào)連接過程中,回調(diào)函數(shù)接收連接的狀態(tài)信息及發(fā)生的錯(cuò)誤代碼?;卣{(diào)函數(shù)的原形如下:VOID WINAPI RasDialFunc(UINT unMsg,RASCONNSTATE rasconnstate,DWORD dwError)
由于在調(diào)用RasDialFunc 函數(shù)時(shí),連接操作被掛起,因此,應(yīng)用程序應(yīng)盡快處理發(fā)生的事件并返回。可以在RasDialFunc 函數(shù)中調(diào)用PostMessage 函數(shù),將事件通知消息送給窗口函數(shù)來處理。
RASDIALPARAMS 結(jié)構(gòu)定義如下:
DWORD dwSize 結(jié)構(gòu)變量的大小。
TCHAR szEntryName[RAS_MaxEntryName +1] 撥號(hào)網(wǎng)絡(luò)中建立的連接名。
TCHAR szPhoneNumber[RAS_MaxPhoneNumber +1] 電話號(hào)碼,若采用szEntryName 中定義的號(hào)碼,置為NULL 值。
TCHAR szCallbackNumber[RAS_MaxCallbackNumber +1] 回?fù)芴?hào)碼,不用時(shí)置為NULL。
TCHAR szUserName[UNLEN +1] 用戶標(biāo)識(shí)。
TCHAR szPassword[PWLEN +1] 用戶口令。
TCHAR szDomain[DNLEN +1] 用戶權(quán)限驗(yàn)證域,若為NULL 采用RAS 服務(wù)器所在的域進(jìn)行驗(yàn)證,若為‘*’采用szEntryName 中定義的域進(jìn)行驗(yàn)證。
RASCONNSTATE 枚舉型結(jié)構(gòu),包含撥號(hào)連接過程中各種可能狀態(tài)的定義。
函數(shù)RasHangUp() 用來終止撥號(hào)連接,因程序需要一定的時(shí)間來結(jié)束連接,應(yīng)用程序調(diào)用該函數(shù)后不能馬上退出,需等待3 秒后才能退出。
二、獲取動(dòng)態(tài)IP 地址API
在VC 中是通過調(diào)用函數(shù)RasGetProjectionInfo() 來獲取IP 地址的。
函數(shù)調(diào)用成功時(shí)返回0 值,此時(shí)在RASPPPIP 結(jié)構(gòu)變量中的szIpAddress 就是動(dòng)態(tài)IP 地址。
三、程序?qū)崿F(xiàn)
程序是在Win 95 環(huán)境下,用VC ++5.0 編寫,并編譯運(yùn)行通過。完整的源程序清單如下:
// ---?。?br />//file name ras.c
// ---?。?br />#include < windows.h >
#include < winuser.h >
#include < string.h >
#include < ras.h >
#include < raserror.h >
#include "resource.h"
// 函數(shù)原形
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 入口函數(shù)
// ---?。?br />int PASCAL WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,LPSTR lpszCmdLine,
int nCmdShow )
{
hInst=hInstance;
if ( DialogBox(hInstance,"RAS_DLG",NULL,
(DLGPROC)DialogProc) == -1 )
MessageBox(NULL,"建立對(duì)話框失敗!",
"TITLE",MB_OK);
return 0;
}
// -----------------
// 對(duì)話框窗口函數(shù)
// -----------------
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 )
// 建立撥號(hào)連接, 成功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;
// 以下開始異步撥叫網(wǎng)絡(luò)
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 異步處理的回調(diào)函數(shù)
// unMsg?。l(fā)生的RAS 事件
// rasconnstate -連接進(jìn)入的狀態(tài)
// dwError ?。l(fā)生的錯(cuò)誤代碼
// ---------------
VOID WINAPI RasDialFunc
( UINT unMsg, RASCONNSTATE rasconnstate,
DWORD dwError )
{
PostMessage(hWin,
WM_RASDIALEVENT,
(WPARAM) rasconnstate,
(LPARAM) dwError );
}
// ----------------
// RasDial() 返回的事件信息由該函數(shù)處理
// ----------------
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 ) // 發(fā)生錯(cuò)誤
{
if ( RasGetErrorString
( (UINT)lparam, szMessage, 256 ) != 0 )
wsprintf( (LPSTR)szMessage,
“出錯(cuò)Undefined RAS Dial Error." );
ShowMsg(hdlg,szMessage);
return TRUE;
}
else if ( RASCS_DONE &wparam ) // 連接成功
{
// 取動(dòng)態(tài)分配的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;
}
// ----------------
// 根據(jù)連接狀態(tài)
取字符串資源中對(duì)應(yīng)的標(biāo)號(hào)
// ----------------
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實(shí)現(xiàn)撥號(hào)上網(wǎng)的程序,今天在網(wǎng)上無意中發(fā)現(xiàn)了這篇文章,于是便轉(zhuǎn)載過來,希望對(duì)這位朋友有所幫助!
正文:
大家知道,在netants、download expert等軟件中都帶有定時(shí)撥號(hào)上網(wǎng)下載軟件的功能。而一般用戶的撥號(hào)上網(wǎng),利用的是windows的remote access service(ras,遠(yuǎn)程訪問服務(wù))。下面介紹一下其在visual c++下的實(shí)現(xiàn)。
visual c++為我們提供了包含ras api聲明的“ras.h″頭文件。要在程序中實(shí)現(xiàn)撥號(hào)上網(wǎng)功能,其大致過程如下:
1. 利用modem撥號(hào)進(jìn)行連接,應(yīng)使用rasdial函數(shù)。
其聲明如下:
dword ras dial(lprasdialextensions lpras dialextensions,lpctstr lpszphonebook,lprasdialparams lp ras dialparams,dword dw notifier type,lpvoid lpv notifier, lphrasconn lph ras conn )
參數(shù)說明:
lprasdialextensions和lpszphonebook:僅在windows nt下有效,在windows 95下,這兩個(gè)參數(shù)被忽略。
lprasdialparams:這個(gè)參數(shù)很重要,它指向一個(gè)rasdialparams結(jié)構(gòu),該結(jié)構(gòu)包含以下幾個(gè)成員:
dwsize:應(yīng)設(shè)定為sizeof(rasdialparams);
szentryname和szphonenumber:這兩個(gè)參數(shù)有聯(lián)系,szentryname可以指定要建立的連接,比方說“我的連接”等等,這是處理用戶已經(jīng)在“撥號(hào)網(wǎng)絡(luò)”里建立的連接的。這時(shí),modem將撥打你在“我的連接”中設(shè)定的isp號(hào)碼,此時(shí)szphonenumber成員設(shè)為空字符串“”即可;如果你要在程序中自行指定要撥打的isp號(hào)碼的話,szentryname可以設(shè)定為空字符串“”,此時(shí)應(yīng)設(shè)置szphonenumber為你的isp號(hào)碼(169,663等),特別的,對(duì)于用201電話卡來上網(wǎng)的情況,可以設(shè)為“201,,,賬號(hào),密碼#,,isp號(hào)碼#”(其中“,”表示停頓一段時(shí)間(以等待確認(rèn)賬號(hào),密碼等),你可以根據(jù)自己所在位置的線路狀況自行調(diào)節(jié)。 szcallbacknumber,szdomain:設(shè)為空串“”即可。 szusername,szpassword:登錄用戶名和密碼。如169公用賬號(hào)guest,guest。
其他成員不必設(shè)置。
dwnotifiertype:指定是由窗口還是由回調(diào)函數(shù)來處理確認(rèn)消息。通過確認(rèn)消息我們可以得到rasdial過程的當(dāng)前狀態(tài)。如“正在打開段口”,“正在驗(yàn)證用戶名和密碼”等。也可設(shè)為null。 dwnotifier:指定處理確認(rèn)消息的窗口或回調(diào)函數(shù)。也可設(shè)為null。
lphrasconn:指向一個(gè)類型為hrasconn的變量。在調(diào)用rasdial前必須指定為null,rasdial若成功返回,則將ras連接的句柄存放于它所指向的變量中。我們也可以通過此句柄來斷開連接。
只要在程序中適當(dāng)位置調(diào)用rasdial函數(shù)即可建立連接。
2. 理確認(rèn)消息以得到撥號(hào)過程的當(dāng)前狀態(tài)。
我們以指定窗口來處理確認(rèn)消息為例說明如何得到撥號(hào)過程的當(dāng)前狀態(tài)。
在處理確認(rèn)消息的對(duì)話框類(或視圖類等)的實(shí)現(xiàn)代碼中加入:
const uint wm_rasevent = ::registerwindowmessagea(rasdialevent);
在message map中手工加入消息映射:(****是你定義的對(duì)話框類名稱)
begin_message_map(****, cdialog)
file://afx_msg_map(****)
……
on_registered_message(wm_rasevent, onrasdialevent)(<-加入此句)
file://afx_msg_map
end_message_map()
加入成員函數(shù)處理消息:
lresult cdialinfo::onrasdialevent(wparam wp, lparam lp)
{
rasconnstate rasstate= (rasconnstate)wp;
clistbox *info =(clistbox *)getdlgitem(idc_infolist);
file://用listbox 控件(id為idc-infolist)來顯示狀態(tài))
switch(rasstate)
{
case rascs_openport:
info→addstring(_t(″打開端口……″));
break;
case rascs_portopened:
info→addstring(_t(″端口已打開.″));
break;
case rascs_connectdevice:
info→addstring(_t(″連接設(shè)備……″));
break;
case rascs_deviceconnected:
info→addstring(_t(″設(shè)備已連接.″));
break;
case rascs_authenticate:
info→addstring(_t(″驗(yàn)證用戶及密碼″));
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://在調(diào)用rasdial時(shí)用指向m_hrasconn的指針作為lphrasconn參數(shù)。
file://既然用m_hrasconn來保存連接句柄,連接斷開后應(yīng)重置為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函數(shù),這里是必需的。需要一定時(shí)間來斷開連接。如果不等待一段時(shí)間,計(jì)算機(jī)有可能無法正常關(guān)閉端口。導(dǎo)致下一次無法撥號(hào),只有重新啟動(dòng)windows才能解決。要預(yù)防此問題也可以調(diào)用rasgetconnectstatus函數(shù),方法如下:
rasconnstatus rstatus;
while(rasgetconnectstatus(m_hrasconn,&rstatus)!=error_invalid_handle)
{
?。海簊leep(0);
}
4.在以下情況下:
① 瀏覽網(wǎng)頁時(shí)有時(shí)會(huì)出現(xiàn)停止響應(yīng),重啟explorer后任務(wù)欄上的連接狀態(tài)圖標(biāo)也許會(huì)消失。
② 希望在連接成功后,退出程序,再次執(zhí)行此程序可選擇斷開連接。
可以調(diào)用rasenumconnection函數(shù)來得到當(dāng)前連接的句柄。
舉例如下:
hrasconn hrasconnect;dword dwbufffersize, dwnumofconnections;//緩沖區(qū)大小,連接數(shù)
lprasconn lprasconn;
lprasconn = new rasconn[3】;//最多可得到3個(gè)連接句柄,客戶端程序其實(shí)不必設(shè)為3,因連接數(shù)有限,大部分僅一個(gè)連接。
lprasconn[0】.dwsize = sizeof(rasconn);
dwbufffersize = 32* sizeof(rasconn);//求出由3個(gè)rasconn結(jié)構(gòu)構(gòu)成的緩沖區(qū)大小
rasenumconnections(lpras conn, &dw buffer size, &dw numof connections);//此函數(shù)若成功則返回零。
for(dword i=0; i {
hrasconnect = lprasconn[i】.hrasconn;//rasconn結(jié)構(gòu)的hrasconn成員為ras連接句柄
rashangup(hrasconnect);
::sleep(2000);
}
delete [】 lprasconn;
在windows 98,visual c++ 6.0下調(diào)試通過。
這樣,一個(gè)實(shí)現(xiàn)基本撥號(hào)上網(wǎng)功能的程序就完成了。如果你要了解更多有關(guān)情況或服務(wù)器端程序設(shè)計(jì),可以參考msdn→platform sdk→networking and distributed services→remote access service的有關(guān)內(nèi)容
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
華麗的分割線---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
背景:代替手工自動(dòng)進(jìn)行PPPOE撥號(hào)
相關(guān)知識(shí):
主要使用的函數(shù):
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.
更多消息請(qǐng)查看 :
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;//需要撥號(hào)的名稱,也就是建立的寬帶連接的名稱,如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);
//指定的撥號(hào)連接。
int a =RasDial(NULL, NULL, ¶ms, NULL, NULL, &handle);
if (a!=ERROR_SUCCESS)
{
MessageBox("正在撥打的計(jì)算機(jī)沒有應(yīng)答,稍后請(qǐng)?jiān)僭?);
Message +="/n"+entryname+"dailying up failed....../n";
UpdateData(TRUE);
DWORD off=RasHangUp(handle);
//SendMessage(WM_CLOSE);
if (off==0)
{
MessageBox("連接已斷開");
//printf("連接已斷開.../n");
}
else{
//printf("斷開連接出錯(cuò).../n");
MessageBox("斷開連接出錯(cuò).");
}
}
C++ 撥號(hào)函數(shù)演示 -
-
-
-
-
-
-
-
-
- #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("已經(jīng)連接上...\n");
-
-
-
-
-
-
-
-
-
-
- return 0;
- }
- printf("連接出錯(cuò)...\n");
- return 0;
|
posted on 2013-03-17 19:51
聶文龍 閱讀(5526)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
Visual C++