CnDialUp.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2007 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnDialUp;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:网络通讯组件包
  24. * 单元名称:拨号组件实现单元
  25. * 单元作者:匿名
  26. * 移 植:Childe Ng
  27. * 备 注:
  28. * 开发平台:PWin2000Pro + Delphi 5.01
  29. * 兼容测试:PWin9X/2000/XP + Delphi 5/6/7 + C++Builder 5/6
  30. * 本 地 化:该单元中的字符串均符合本地化处理方式
  31. * 单元标识:$Id$
  32. * 修改记录:2008.06.03 V1.0
  33. * 创建单元
  34. ================================================================================
  35. |</PRE>}
  36. interface
  37. {$I CnPack.inc}
  38. uses
  39. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  40. ExtCtrls, WinInet;
  41. const
  42. DNLEN = 15;
  43. UNLEN = 256;
  44. PWLEN = 256;
  45. RAS_MaxEntryName = 256;
  46. RAS_MaxDeviceType = 16;
  47. RAS_MaxDeviceName = 128;
  48. RAS_MaxPhoneNumber = 128;
  49. RAS_MaxCallbackNumber = RAS_MaxPhoneNumber;
  50. RASCS_PAUSED = $1000;
  51. RASCS_DONE = $2000;
  52. RASCS_OpenPort = 0;
  53. RASCS_PortOpened = 1;
  54. RASCS_ConnectDevice = 2;
  55. RASCS_DeviceConnected = 3;
  56. RASCS_AllDevicesConnected = 4;
  57. RASCS_Authenticate = 5;
  58. RASCS_AuthNotify = 6;
  59. RASCS_AuthRetry = 7;
  60. RASCS_AuthCallback = 8;
  61. RASCS_AuthChangePassword = 9;
  62. RASCS_AuthProject = 10;
  63. RASCS_AuthLinkSpeed = 11;
  64. RASCS_AuthAck = 12;
  65. RASCS_ReAuthenticate = 13;
  66. RASCS_Authenticated = 14;
  67. RASCS_PrepareForCallback = 15;
  68. RASCS_WaitForModemReset = 16;
  69. RASCS_WaitForCallback = 17;
  70. RASCS_Projected = 18;
  71. RASCS_StartAuthentication = 19;
  72. RASCS_CallbackComplete = 20;
  73. RASCS_LogonNetwork = 21;
  74. RASCS_Interactive = RASCS_PAUSED;
  75. RASCS_RetryAuthentication = RASCS_PAUSED + 1;
  76. RASCS_CallbackSetByCaller = RASCS_PAUSED + 2;
  77. RASCS_PasswordExpired = RASCS_PAUSED + 3;
  78. RASCS_Connected = RASCS_DONE;
  79. RASCS_Disconnected = RASCS_DONE + 1;
  80. type
  81. THRasConn = Longint;
  82. LPRasConnA = ^TRasConnA;
  83. TRasConnA = record
  84. dwSize: Longint;
  85. hrasconn: THRasConn;
  86. szEntryName: array[0..RAS_MaxEntryName] of AnsiChar;
  87. szDeviceType: array[0..RAS_MaxDeviceType] of AnsiChar;
  88. szDeviceName: array[0..RAS_MaxDeviceName] of AnsiChar;
  89. end;
  90. LPRasConn = ^TRasConn;
  91. TRasConn = TRasConnA;
  92. LPRasConnState = ^TRasConnState;
  93. TRasConnState = Integer;
  94. LPRasConnStatusA = ^TRasConnStatusA;
  95. TRasConnStatusA = record
  96. dwSize: Longint;
  97. rasconnstate: TRasConnState;
  98. dwError: Longint;
  99. szDeviceType: array[0..RAS_MaxDeviceType] of AnsiChar;
  100. szDeviceName: array[0..RAS_MaxDeviceName] of AnsiChar;
  101. end;
  102. LPRasConnStatus = ^TRasConnStatus;
  103. TRasConnStatus = TRasConnStatusA;
  104. LPRasEntryNameA = ^TRasEntryNameA;
  105. TRasEntryNameA = record
  106. dwSize: Longint;
  107. szEntryName: array[0..RAS_MaxEntryName] of AnsiChar;
  108. end;
  109. LPRasEntryName = ^TRasEntryName;
  110. TRasEntryName = TRasEntryNameA;
  111. LPRasDialParamsA = ^TRasDialParamsA;
  112. TRasDialParamsA = record
  113. dwSize: Longint;
  114. szEntryName: array[0..RAS_MaxEntryName] of AnsiChar;
  115. szPhoneNumber: array[0..RAS_MaxPhoneNumber] of AnsiChar;
  116. szCallbackNumber: array[0..RAS_MaxCallbackNumber] of AnsiChar;
  117. szUserName: array[0..UNLEN] of AnsiChar;
  118. szPassword: array[0..PWLEN] of AnsiChar;
  119. szDomain: array[0..DNLEN] of AnsiChar;
  120. end;
  121. LPRasDialParams = ^TRasDialParams;
  122. TRasDialParams = TRasDialParamsA;
  123. LPRasDialExtensions = ^TRasDialExtensions;
  124. TRasDialExtensions = record
  125. dwSize: Longint;
  126. dwfOptions: Longint;
  127. hwndParent: HWnd;
  128. reserved: Longint;
  129. end;
  130. type
  131. TOnStatusEvent = procedure(Sender: TObject; MessageText: string; Error: Boolean) of object;
  132. TCnDialUp = class(TComponent)
  133. private
  134. FTimer: TTimer;
  135. FPassword: string;
  136. FUsername: string;
  137. FConnectTo: string;
  138. hRasDLL: THandle;
  139. StatusStr: string;
  140. ErrorStat: Boolean;
  141. AsyncStatus: Boolean;
  142. FLangStrList: TStringList;
  143. FPossibleConnections: TStringList;
  144. FOnStatusEvent: TOnStatusEvent;
  145. function StatusString(State: TRasConnState; Error: Integer; var ES: Boolean): string;
  146. function GetActiveConnection: string;
  147. procedure SetLangStrList(Value: TStringList);
  148. function GetCurrentConnection: string;
  149. function GetPossibleConnections: TStringList;
  150. procedure GetConnections(var SL: TStringList);
  151. function GetRasInstalled: Boolean;
  152. function GetOnlineStatus: Boolean;
  153. protected
  154. procedure Timer(Sender: TObject); virtual;
  155. public
  156. constructor Create(AOwner: TComponent); override;
  157. destructor Destroy; override;
  158. function GoOnline: Boolean;
  159. procedure GoOffline;
  160. published
  161. property IsOnline: Boolean read GetOnlineStatus;
  162. {* 检查是否连接了网络}
  163. property Password: string read FPassword write FPassword;
  164. {* 拨号连接的密码}
  165. property Username: string read FUsername write FUsername;
  166. {* 拨号连接的用户名}
  167. property CurrentConnection: string read GetCurrentConnection;
  168. {* 当前网络连接名称}
  169. property ConnectTo: string read FConnectTo write FConnectTo;
  170. {* 需要连接到的连接名称}
  171. property PossibleConnections: TStringList read GetPossibleConnections;
  172. {* 所有可用的拨号连接}
  173. property LangStrList: TStringList read FLangStrList write SetLangStrList;
  174. {* 用户交互界面,可多语化处理}
  175. property OnStatusEvent: TOnStatusEvent read FOnStatusEvent write FOnStatusEvent;
  176. {* 发生连接或断开连接时触发的事件}
  177. property RasInstalled: Boolean read GetRasInstalled;
  178. {* 检查运行环境}
  179. end;
  180. implementation
  181. var
  182. xSelf: Pointer;
  183. RasHangUp: function(hConn: THRasConn): Longint; stdcall;
  184. RasEnumConnections: function(RasConnArray: LPRasConn; var lpcb: Longint; var lpcConnections: Longint): Longint; stdcall;
  185. RasGetConnectStatus: function(hConn: THRasConn; var lpStatus: TRasConnStatus): Longint; stdcall;
  186. RasEnumEntries: function(reserved: PAnsiChar; lpszPhoneBook: PAnsiChar; EntryNamesArray: LPRasEntryNameA; var lpcb: Longint; var lpcEntries: Longint): Longint; stdcall;
  187. RasGetEntryDialParams: function(lpszPhoneBook: PAnsiChar; var lpDialParams: TRasDialParams; var lpfPassword: LongBool): Longint; stdcall;
  188. RasGetErrorString: function(ErrorValue: Integer; ErrorString: PAnsiChar; cBufSize: Longint): Longint; stdcall;
  189. RasDial: function(lpRasDialExt: LPRasDialExtensions; lpszPhoneBook: PAnsiChar; var Params: TRasDialParams; dwNotifierType: Longint; lpNotifier: Pointer; var RasConn: THRasConn): Longint; stdcall;
  190. RasSetEntryDialParams: function(lpszPhoneBook: PAnsiChar; var lpDialParams: TRasDialParams; fRemovePassword: LongBool): Longint; stdcall;
  191. procedure TCnDialUp.Timer(Sender: TObject);
  192. begin
  193. FTimer.Enabled := False;
  194. if AsyncStatus = False then Exit;
  195. if Assigned(FOnStatusEvent) then
  196. FOnStatusEvent(TCnDialUp(xSelf), StatusStr, ErrorStat);
  197. AsyncStatus := False;
  198. end;
  199. procedure RasCallback(Msg: Integer; State: TRasConnState; Error: Integer); stdcall;
  200. begin
  201. while TCnDialUp(xSelf).AsyncStatus = True do ;
  202. TCnDialUp(xSelf).AsyncStatus := True;
  203. TCnDialUp(xSelf).FTimer.Enabled := True;
  204. TCnDialUp(xSelf).StatusStr := TCnDialUp(xSelf).StatusString(State, Error, TCnDialUp(xSelf).ErrorStat);
  205. end;
  206. constructor TCnDialUp.Create(AOwner: TComponent);
  207. begin
  208. inherited Create(AOwner);
  209. AsyncStatus := False;
  210. FTimer := TTimer.Create(Self);
  211. FTimer.Enabled := False;
  212. FTimer.Interval := 1;
  213. FTimer.OnTimer := Timer;
  214. FPossibleConnections := TStringList.Create;
  215. FLangStrList := TStringList.Create;
  216. FLangStrList.Add('Connecting to %s...');
  217. FLangStrList.Add('Verifying username and password...');
  218. FLangStrList.Add('An error occured while trying to connect to %s.');
  219. // Attempt to load the RASAPI32 DLL. If the DLL loads, hRasDLL will
  220. // be non-zero. Otherwise, hRasDLL will be zero.
  221. hRasDLL := LoadLibrary('RASAPI32.DLL');
  222. // Assign function pointers for the RAS functions.
  223. if hRasDLL < 1 then Exit;
  224. @RasEnumConnections := GetProcAddress(hRasDLL, 'RasEnumConnectionsA');
  225. @RasHangUp := GetProcAddress(hRasDLL, 'RasHangUpA');
  226. @RasGetConnectStatus := GetProcAddress(hRasDLL, 'RasGetConnectStatusA');
  227. @RasEnumEntries := GetProcAddress(hRasDLL, 'RasEnumEntriesA');
  228. @RasGetEntryDialParams := GetProcAddress(hRasDLL, 'RasGetEntryDialParamsA');
  229. @RasGetErrorString := GetProcAddress(hRasDLL, 'RasGetErrorStringA');
  230. @RasDial := GetProcAddress(hRasDLL, 'RasDialA');
  231. @RasSetEntryDialParams := GetProcAddress(hRasDLL, 'RasSetEntryDialParamsA');
  232. end;
  233. destructor TCnDialUp.Destroy;
  234. begin
  235. // If the RASAPI32 DLL was loaded, then free it.
  236. if RasInstalled then
  237. FreeLibrary(hRasDLL);
  238. FLangStrList.Free;
  239. FPossibleConnections.Free;
  240. FTimer.Free;
  241. inherited Destroy;
  242. end;
  243. function TCnDialUp.GetRasInstalled: Boolean;
  244. // Determines if RAS has been installed by checking for DLL handle. If RAS
  245. // has not been installed, hRasDLL is zero.
  246. begin
  247. Result := hRasDLL <> 0;
  248. end;
  249. function TCnDialUp.GetCurrentConnection: string;
  250. begin
  251. Result := GetActiveConnection;
  252. end;
  253. function TCnDialUp.GetPossibleConnections: TStringList;
  254. begin
  255. FPossibleConnections.Clear;
  256. GetConnections(FPossibleConnections);
  257. Result := FPossibleConnections;
  258. end;
  259. procedure TCnDialUp.SetLangStrList(Value: TStringList);
  260. begin
  261. FLangStrList.Assign(Value);
  262. end;
  263. function TCnDialUp.GoOnline: Boolean;
  264. var
  265. hRAS: THRasConn;
  266. B: LongBool;
  267. R: Integer;
  268. C: array[0..100] of Char;
  269. DialParams: TRasDialParams;
  270. begin
  271. Result := False;
  272. if not RasInstalled then Exit;
  273. try
  274. GoOffline;
  275. FillChar(DialParams, SizeOf(TRasDialParams), 0);
  276. DialParams.dwSize := SizeOf(TRasDialParams);
  277. StrPCopy(DialParams.szEntryName, {$IFDEF UNICODE}AnsiString{$ENDIF}(FConnectTo));
  278. B := False;
  279. R := RasGetEntryDialParams(nil, DialParams, B);
  280. if R <> 0 then
  281. begin
  282. Result := False;
  283. GoOffline;
  284. if Assigned(FOnStatusEvent) then
  285. FOnStatusEvent(Self, FLangStrList[2], True);
  286. Exit;
  287. end;
  288. DialParams.dwSize := SizeOf(TRasDialParams);
  289. StrPCopy(DialParams.szUserName, {$IFDEF UNICODE}AnsiString{$ENDIF}(FUsername));
  290. StrPCopy(DialParams.szPassword, {$IFDEF UNICODE}AnsiString{$ENDIF}(FPassword));
  291. R := RasSetEntryDialParams(nil, DialParams, False);
  292. if R <> 0 then
  293. begin
  294. Result := False;
  295. GoOffline;
  296. if Assigned(FOnStatusEvent) then
  297. FOnStatusEvent(Self, FLangStrList[2], True);
  298. Exit;
  299. end;
  300. xSelf := Self;
  301. AsyncStatus := False;
  302. hRAS := 0;
  303. R := RasDial(nil, nil, DialParams, 0, @RasCallback, hRAS);
  304. if R <> 0 then
  305. begin
  306. Result := False;
  307. RasGetErrorString(R, PAnsiChar({$IFDEF UNICODE}AnsiString{$ELSE}string{$ENDIF}(C)), 100);
  308. GoOffline;
  309. if Assigned(FOnStatusEvent) then
  310. FOnStatusEvent(Self, C, True);
  311. Exit;
  312. end;
  313. Result := True;
  314. except
  315. on E: Exception do
  316. begin
  317. GoOffline;
  318. if Assigned(FOnStatusEvent) then
  319. FOnStatusEvent(Self, E.Message, True);
  320. end;
  321. end;
  322. end;
  323. procedure TCnDialUp.GetConnections(var SL: TStringList);
  324. var
  325. BuffSize, Entries, R, I: Integer;
  326. Entry: array[1..100] of TRasEntryName;
  327. begin
  328. if not RasInstalled then Exit;
  329. SL.Clear;
  330. Entry[1].dwSize := SizeOf(TRasEntryName);
  331. BuffSize := SizeOf(TRasEntryName) * 100;
  332. R := RasEnumEntries(nil, nil, @Entry[1], BuffSize, Entries);
  333. if (R = 0) and (Entries > 0) then
  334. for I := 1 to Entries do SL.Add({$IFDEF UNICODE}String{$ENDIF}(Entry[I].szEntryName));
  335. end;
  336. function TCnDialUp.GetActiveConnection: string;
  337. var
  338. BufSize, NumEntries, I, R: Integer;
  339. Entries: array[1..100] of TRasConn;
  340. Stat: TRasConnStatus;
  341. begin
  342. Result := '';
  343. if not RasInstalled then Exit;
  344. Entries[1].dwSize := SizeOf(TRasConn);
  345. BufSize := SizeOf(TRasConn) * 100;
  346. FillChar(Stat, SizeOf(TRasConnStatus), 0);
  347. Stat.dwSize := SizeOf(TRasConnStatus);
  348. R := RasEnumConnections(@Entries[1], BufSize, NumEntries);
  349. if R = 0 then
  350. if NumEntries > 0 then
  351. for I := 1 to NumEntries do begin
  352. RasGetConnectStatus(Entries[I].hrasconn, Stat);
  353. if Stat.rasconnstate = RASCS_Connected then
  354. Result := Entries[I].szEntryName + ' (' + {$IFDEF UNICODE}string{$ENDIF}(Entries[I].szDeviceName) + ')'
  355. end;
  356. end;
  357. procedure TCnDialUp.GoOffline;
  358. var
  359. Entries: array[1..100] of TRasConn;
  360. BufSize, NumEntries, R, I, E: Integer;
  361. begin
  362. if not RasInstalled then Exit;
  363. for E := 0 to 6 do begin
  364. Entries[1].dwSize := SizeOf(TRasConn);
  365. R := RasEnumConnections(@Entries[1], BufSize, NumEntries);
  366. if R = 0 then begin
  367. if NumEntries > 0 then
  368. for I := 1 to NumEntries do RasHangUp(Entries[I].hrasconn);
  369. end;
  370. Application.ProcessMessages;
  371. end;
  372. end;
  373. function TCnDialUp.StatusString(State: TRasConnState; Error: Integer; var ES: Boolean): string;
  374. var
  375. C: array[0..100] of Char;
  376. S: string;
  377. begin
  378. S := 'Something went wrong...';
  379. ES := False;
  380. if not RasInstalled then Exit;
  381. if Error <> 0 then
  382. begin
  383. RasGetErrorString(Error, PAnsiChar({$IFDEF UNICODE}AnsiString{$ELSE}string{$ENDIF}(C)), 100);
  384. ES := True;
  385. S := C;
  386. end
  387. else
  388. begin
  389. case State of
  390. //connecting
  391. RASCS_OpenPort, RASCS_PortOpened, RASCS_ConnectDevice, RASCS_DeviceConnected,
  392. RASCS_AllDevicesConnected, RASCS_PrepareForCallback, RASCS_WaitForModemReset,
  393. RASCS_WaitForCallback, RASCS_Projected, RASCS_CallbackComplete, RASCS_LogonNetwork,
  394. RASCS_Interactive, RASCS_CallbackSetByCaller, RASCS_Connected: S := Format(FLangStrList[0], [FConnectTo]);
  395. //authenticateing
  396. RASCS_Authenticate, RASCS_StartAuthentication, RASCS_Authenticated: S := FLangStrList[1];
  397. //error
  398. RASCS_AuthNotify, RASCS_AuthRetry, RASCS_AuthCallback, RASCS_AuthChangePassword,
  399. RASCS_AuthProject, RASCS_AuthLinkSpeed, RASCS_AuthAck, RASCS_ReAuthenticate,
  400. RASCS_RetryAuthentication, RASCS_Disconnected, RASCS_PasswordExpired: S := Format(FLangStrList[2], [FConnectTo]);
  401. end;
  402. end;
  403. Result := S;
  404. end;
  405. function TCnDialUp.GetOnlineStatus: Boolean;
  406. var
  407. Types: Integer;
  408. begin
  409. Types := INTERNET_CONNECTION_MODEM +
  410. INTERNET_CONNECTION_LAN + INTERNET_CONNECTION_PROXY;
  411. Result := InternetGetConnectedState(@Types, 0);
  412. end;
  413. end.