]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dialup.cpp
fixes #12220
[wxWidgets.git] / src / msw / dialup.cpp
CommitLineData
a0b4c98b 1/////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/msw/dialup.cpp
a0b4c98b
VZ
3// Purpose: MSW implementation of network/dialup classes and functions
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 07.07.99
7// RCS-ID: $Id$
8// Copyright: (c) Vadim Zeitlin
65571936 9// Licence: wxWindows licence
a0b4c98b
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// for compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
a0b4c98b
VZ
27#if wxUSE_DIALUP_MANAGER
28
670f9935
WS
29#include "wx/dialup.h"
30
a0b4c98b
VZ
31#ifndef WX_PRECOMP
32 #include "wx/log.h"
d1f4970d
VZ
33 #include "wx/intl.h"
34 #include "wx/event.h"
670f9935 35 #include "wx/app.h"
c0badb70 36 #include "wx/timer.h"
02761f6c 37 #include "wx/module.h"
a0b4c98b
VZ
38#endif
39
fcec6429
VZ
40#include "wx/generic/choicdgg.h"
41
142ae7b3 42#include "wx/msw/private.h"
a0b4c98b 43#include "wx/dynlib.h"
a0b4c98b 44
9b11752c
VZ
45wxDEFINE_EVENT( wxEVT_DIALUP_CONNECTED, wxDialUpEvent );
46wxDEFINE_EVENT( wxEVT_DIALUP_DISCONNECTED, wxDialUpEvent );
2e4df4bf 47
3bce6687
JS
48// Doesn't yet compile under VC++ 4, BC++, Watcom C++,
49// Wine: no wininet.h
3aabb24c 50#if (!defined(__BORLANDC__) || (__BORLANDC__>=0x550)) && \
ce20b5d7 51 (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \
7ba4fbeb 52 !defined(__GNUWIN32_OLD__) && \
5283098e 53 !defined(__WINE__) && \
7ba4fbeb 54 (!defined(__VISUALC__) || (__VISUALC__ >= 1020))
106f0395 55
a0b4c98b
VZ
56#include <ras.h>
57#include <raserror.h>
58
2690830e
VZ
59#include <wininet.h>
60
a2327a9f
JS
61// Not in VC++ 5
62#ifndef INTERNET_CONNECTION_LAN
63#define INTERNET_CONNECTION_LAN 2
64#endif
65#ifndef INTERNET_CONNECTION_PROXY
66#define INTERNET_CONNECTION_PROXY 4
67#endif
68
8563c6f1
VZ
69// implemented in utils.cpp
70extern "C" WXDLLIMPEXP_BASE HWND
71wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
72
73static const wxChar *
74 wxMSWDIALUP_WNDCLASSNAME = wxT("_wxDialUpManager_Internal_Class");
75static const wxChar *gs_classForDialUpWindow = NULL;
76
a0b4c98b
VZ
77// ----------------------------------------------------------------------------
78// constants
79// ----------------------------------------------------------------------------
80
81// this message is sent by the secondary thread when RAS status changes
82#define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
2690830e 83#define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011)
a0b4c98b
VZ
84
85// ----------------------------------------------------------------------------
86// types
87// ----------------------------------------------------------------------------
88
89// the signatures of RAS functions: all this is quite heavy, but we must do it
90// to allow running wxWin programs on machine which don't have RAS installed
91// (this does exist) - if we link with rasapi32.lib, the program will fail on
92// startup because of the missing DLL...
93
94#ifndef UNICODE
2690830e
VZ
95 typedef DWORD (APIENTRY * RASDIAL)( LPRASDIALEXTENSIONS, LPCSTR, LPRASDIALPARAMSA, DWORD, LPVOID, LPHRASCONN );
96 typedef DWORD (APIENTRY * RASENUMCONNECTIONS)( LPRASCONNA, LPDWORD, LPDWORD );
97 typedef DWORD (APIENTRY * RASENUMENTRIES)( LPCSTR, LPCSTR, LPRASENTRYNAMEA, LPDWORD, LPDWORD );
98 typedef DWORD (APIENTRY * RASGETCONNECTSTATUS)( HRASCONN, LPRASCONNSTATUSA );
99 typedef DWORD (APIENTRY * RASGETERRORSTRING)( UINT, LPSTR, DWORD );
100 typedef DWORD (APIENTRY * RASHANGUP)( HRASCONN );
101 typedef DWORD (APIENTRY * RASGETPROJECTIONINFO)( HRASCONN, RASPROJECTION, LPVOID, LPDWORD );
102 typedef DWORD (APIENTRY * RASCREATEPHONEBOOKENTRY)( HWND, LPCSTR );
103 typedef DWORD (APIENTRY * RASEDITPHONEBOOKENTRY)( HWND, LPCSTR, LPCSTR );
104 typedef DWORD (APIENTRY * RASSETENTRYDIALPARAMS)( LPCSTR, LPRASDIALPARAMSA, BOOL );
105 typedef DWORD (APIENTRY * RASGETENTRYDIALPARAMS)( LPCSTR, LPRASDIALPARAMSA, LPBOOL );
106 typedef DWORD (APIENTRY * RASENUMDEVICES)( LPRASDEVINFOA, LPDWORD, LPDWORD );
107 typedef DWORD (APIENTRY * RASGETCOUNTRYINFO)( LPRASCTRYINFOA, LPDWORD );
108 typedef DWORD (APIENTRY * RASGETENTRYPROPERTIES)( LPCSTR, LPCSTR, LPRASENTRYA, LPDWORD, LPBYTE, LPDWORD );
109 typedef DWORD (APIENTRY * RASSETENTRYPROPERTIES)( LPCSTR, LPCSTR, LPRASENTRYA, DWORD, LPBYTE, DWORD );
110 typedef DWORD (APIENTRY * RASRENAMEENTRY)( LPCSTR, LPCSTR, LPCSTR );
111 typedef DWORD (APIENTRY * RASDELETEENTRY)( LPCSTR, LPCSTR );
112 typedef DWORD (APIENTRY * RASVALIDATEENTRYNAME)( LPCSTR, LPCSTR );
113 typedef DWORD (APIENTRY * RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD );
a0b4c98b 114
9a83f860 115 static const wxChar gs_funcSuffix = wxT('A');
a0b4c98b 116#else // Unicode
2690830e
VZ
117 typedef DWORD (APIENTRY * RASDIAL)( LPRASDIALEXTENSIONS, LPCWSTR, LPRASDIALPARAMSW, DWORD, LPVOID, LPHRASCONN );
118 typedef DWORD (APIENTRY * RASENUMCONNECTIONS)( LPRASCONNW, LPDWORD, LPDWORD );
119 typedef DWORD (APIENTRY * RASENUMENTRIES)( LPCWSTR, LPCWSTR, LPRASENTRYNAMEW, LPDWORD, LPDWORD );
120 typedef DWORD (APIENTRY * RASGETCONNECTSTATUS)( HRASCONN, LPRASCONNSTATUSW );
121 typedef DWORD (APIENTRY * RASGETERRORSTRING)( UINT, LPWSTR, DWORD );
122 typedef DWORD (APIENTRY * RASHANGUP)( HRASCONN );
123 typedef DWORD (APIENTRY * RASGETPROJECTIONINFO)( HRASCONN, RASPROJECTION, LPVOID, LPDWORD );
124 typedef DWORD (APIENTRY * RASCREATEPHONEBOOKENTRY)( HWND, LPCWSTR );
125 typedef DWORD (APIENTRY * RASEDITPHONEBOOKENTRY)( HWND, LPCWSTR, LPCWSTR );
126 typedef DWORD (APIENTRY * RASSETENTRYDIALPARAMS)( LPCWSTR, LPRASDIALPARAMSW, BOOL );
127 typedef DWORD (APIENTRY * RASGETENTRYDIALPARAMS)( LPCWSTR, LPRASDIALPARAMSW, LPBOOL );
128 typedef DWORD (APIENTRY * RASENUMDEVICES)( LPRASDEVINFOW, LPDWORD, LPDWORD );
129 typedef DWORD (APIENTRY * RASGETCOUNTRYINFO)( LPRASCTRYINFOW, LPDWORD );
130 typedef DWORD (APIENTRY * RASGETENTRYPROPERTIES)( LPCWSTR, LPCWSTR, LPRASENTRYW, LPDWORD, LPBYTE, LPDWORD );
131 typedef DWORD (APIENTRY * RASSETENTRYPROPERTIES)( LPCWSTR, LPCWSTR, LPRASENTRYW, DWORD, LPBYTE, DWORD );
132 typedef DWORD (APIENTRY * RASRENAMEENTRY)( LPCWSTR, LPCWSTR, LPCWSTR );
133 typedef DWORD (APIENTRY * RASDELETEENTRY)( LPCWSTR, LPCWSTR );
134 typedef DWORD (APIENTRY * RASVALIDATEENTRYNAME)( LPCWSTR, LPCWSTR );
135 typedef DWORD (APIENTRY * RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD );
a0b4c98b 136
9a83f860 137 static const wxChar gs_funcSuffix = wxT('W');
a0b4c98b
VZ
138#endif // ASCII/Unicode
139
140// structure passed to the secondary thread
3b415ba4 141struct WXDLLEXPORT wxRasThreadData
a0b4c98b
VZ
142{
143 wxRasThreadData()
144 {
145 hWnd = 0;
97247d36
VZ
146 hEventRas =
147 hEventQuit = 0;
a0b4c98b
VZ
148 dialUpManager = NULL;
149 }
150
97247d36
VZ
151 ~wxRasThreadData()
152 {
153 if ( hWnd )
154 DestroyWindow(hWnd);
155
156 if ( hEventQuit )
157 CloseHandle(hEventQuit);
158
159 if ( hEventRas )
160 CloseHandle(hEventRas);
161 }
162
a0b4c98b 163 HWND hWnd; // window to send notifications to
97247d36
VZ
164 HANDLE hEventRas, // automatic event which RAS signals when status changes
165 hEventQuit; // manual event which we signal when we terminate
a0b4c98b 166
fb1a4789 167 class WXDLLIMPEXP_FWD_CORE wxDialUpManagerMSW *dialUpManager; // the owner
a0b4c98b
VZ
168};
169
170// ----------------------------------------------------------------------------
171// wxDialUpManager class for MSW
172// ----------------------------------------------------------------------------
173
174class WXDLLEXPORT wxDialUpManagerMSW : public wxDialUpManager
175{
176public:
177 // ctor & dtor
178 wxDialUpManagerMSW();
179 virtual ~wxDialUpManagerMSW();
180
181 // implement base class pure virtuals
182 virtual bool IsOk() const;
2690830e 183 virtual size_t GetISPNames(wxArrayString& names) const;
a0b4c98b
VZ
184 virtual bool Dial(const wxString& nameOfISP,
185 const wxString& username,
186 const wxString& password,
187 bool async);
188 virtual bool IsDialing() const;
189 virtual bool CancelDialing();
190 virtual bool HangUp();
2690830e 191 virtual bool IsAlwaysOnline() const;
a0b4c98b 192 virtual bool IsOnline() const;
d71cc120 193 virtual void SetOnlineStatus(bool isOnline = true);
a0b4c98b
VZ
194 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds);
195 virtual void DisableAutoCheckOnlineStatus();
196 virtual void SetWellKnownHost(const wxString& hostname, int port);
197 virtual void SetConnectCommand(const wxString& commandDial,
198 const wxString& commandHangup);
199
200 // for RasTimer
201 void CheckRasStatus();
202
203 // for wxRasStatusWindowProc
204 void OnConnectStatusChange();
2690830e 205 void OnDialProgress(RASCONNSTATE rasconnstate, DWORD dwError);
a0b4c98b
VZ
206
207 // for wxRasDialFunc
2690830e 208 static HWND GetRasWindow() { return ms_hwndRas; }
8563c6f1 209 static void ResetRasWindow() { ms_hwndRas = NULL; }
a0b4c98b
VZ
210 static wxDialUpManagerMSW *GetDialer() { return ms_dialer; }
211
212private:
213 // return the error string for the given RAS error code
214 static wxString GetErrorString(DWORD error);
215
216 // find the (first) handle of the active connection
217 static HRASCONN FindActiveConnection();
218
219 // notify the application about status change
d71cc120 220 void NotifyApp(bool connected, bool fromOurselves = false) const;
a0b4c98b
VZ
221
222 // destroy the thread data and the thread itself
223 void CleanUpThreadData();
224
6bba111c
VZ
225 // number of times EnableAutoCheckOnlineStatus() had been called minus the
226 // number of times DisableAutoCheckOnlineStatus() had been called
227 int m_autoCheckLevel;
228
a0b4c98b 229 // timer used for polling RAS status
3b415ba4 230 class WXDLLEXPORT RasTimer : public wxTimer
a0b4c98b
VZ
231 {
232 public:
233 RasTimer(wxDialUpManagerMSW *dialUpManager)
234 { m_dialUpManager = dialUpManager; }
235
236 virtual void Notify() { m_dialUpManager->CheckRasStatus(); }
237
238 private:
239 wxDialUpManagerMSW *m_dialUpManager;
2eb10e2a 240
c0c133e1 241 wxDECLARE_NO_COPY_CLASS(RasTimer);
a0b4c98b
VZ
242 } m_timerStatusPolling;
243
244 // thread handle for the thread sitting on connection change event
245 HANDLE m_hThread;
246
247 // data used by this thread and our hidden window to send messages between
248 // each other
97247d36 249 wxRasThreadData *m_data;
a0b4c98b 250
4f89dbc4 251 // the handle of rasapi32.dll when it's loaded
4522bb3e 252 wxDynamicLibrary m_dllRas;
4f89dbc4 253
2690830e
VZ
254 // the hidden window we use for passing messages between threads
255 static HWND ms_hwndRas;
256
a0b4c98b
VZ
257 // the handle of the connection we initiated or 0 if none
258 static HRASCONN ms_hRasConnection;
259
a0b4c98b
VZ
260 // the pointers to RAS functions
261 static RASDIAL ms_pfnRasDial;
262 static RASENUMCONNECTIONS ms_pfnRasEnumConnections;
263 static RASENUMENTRIES ms_pfnRasEnumEntries;
264 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus;
265 static RASGETERRORSTRING ms_pfnRasGetErrorString;
266 static RASHANGUP ms_pfnRasHangUp;
267 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo;
268 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry;
269 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry;
270 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams;
271 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams;
272 static RASENUMDEVICES ms_pfnRasEnumDevices;
273 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo;
274 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties;
275 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties;
276 static RASRENAMEENTRY ms_pfnRasRenameEntry;
277 static RASDELETEENTRY ms_pfnRasDeleteEntry;
278 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName;
279
280 // this function is not supported by Win95
281 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification;
282
283 // if this flag is different from -1, it overrides IsOnline()
284 static int ms_userSpecifiedOnlineStatus;
285
286 // this flag tells us if we're online
287 static int ms_isConnected;
288
289 // this flag tells us whether a call to RasDial() is in progress
290 static wxDialUpManagerMSW *ms_dialer;
2eb10e2a 291
c0c133e1 292 wxDECLARE_NO_COPY_CLASS(wxDialUpManagerMSW);
a0b4c98b
VZ
293};
294
8563c6f1
VZ
295// module to destroy helper window created by wxDialUpManagerMSW
296class wxDialUpManagerModule : public wxModule
297{
298public:
299 bool OnInit() { return true; }
300 void OnExit()
301 {
302 HWND hwnd = wxDialUpManagerMSW::GetRasWindow();
303 if ( hwnd )
304 {
305 ::DestroyWindow(hwnd);
306 wxDialUpManagerMSW::ResetRasWindow();
307 }
308
309 if ( gs_classForDialUpWindow )
310 {
311 ::UnregisterClass(wxMSWDIALUP_WNDCLASSNAME, wxGetInstance());
312 gs_classForDialUpWindow = NULL;
313 }
314 }
315
316private:
317 DECLARE_DYNAMIC_CLASS(wxDialUpManagerModule)
318};
319
320IMPLEMENT_DYNAMIC_CLASS(wxDialUpManagerModule, wxModule)
321
a0b4c98b
VZ
322// ----------------------------------------------------------------------------
323// private functions
324// ----------------------------------------------------------------------------
325
326static LRESULT WINAPI wxRasStatusWindowProc(HWND hWnd, UINT message,
327 WPARAM wParam, LPARAM lParam);
328
329static DWORD wxRasMonitorThread(wxRasThreadData *data);
330
331static void WINAPI wxRasDialFunc(UINT unMsg,
332 RASCONNSTATE rasconnstate,
333 DWORD dwError);
334
335// ============================================================================
336// implementation
337// ============================================================================
338
339// ----------------------------------------------------------------------------
340// init the static variables
341// ----------------------------------------------------------------------------
342
343HRASCONN wxDialUpManagerMSW::ms_hRasConnection = 0;
344
2690830e
VZ
345HWND wxDialUpManagerMSW::ms_hwndRas = 0;
346
a0b4c98b
VZ
347RASDIAL wxDialUpManagerMSW::ms_pfnRasDial = 0;
348RASENUMCONNECTIONS wxDialUpManagerMSW::ms_pfnRasEnumConnections = 0;
349RASENUMENTRIES wxDialUpManagerMSW::ms_pfnRasEnumEntries = 0;
350RASGETCONNECTSTATUS wxDialUpManagerMSW::ms_pfnRasGetConnectStatus = 0;
351RASGETERRORSTRING wxDialUpManagerMSW::ms_pfnRasGetErrorString = 0;
352RASHANGUP wxDialUpManagerMSW::ms_pfnRasHangUp = 0;
353RASGETPROJECTIONINFO wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo = 0;
354RASCREATEPHONEBOOKENTRY wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry = 0;
355RASEDITPHONEBOOKENTRY wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry = 0;
356RASSETENTRYDIALPARAMS wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams = 0;
357RASGETENTRYDIALPARAMS wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams = 0;
358RASENUMDEVICES wxDialUpManagerMSW::ms_pfnRasEnumDevices = 0;
359RASGETCOUNTRYINFO wxDialUpManagerMSW::ms_pfnRasGetCountryInfo = 0;
360RASGETENTRYPROPERTIES wxDialUpManagerMSW::ms_pfnRasGetEntryProperties = 0;
361RASSETENTRYPROPERTIES wxDialUpManagerMSW::ms_pfnRasSetEntryProperties = 0;
362RASRENAMEENTRY wxDialUpManagerMSW::ms_pfnRasRenameEntry = 0;
363RASDELETEENTRY wxDialUpManagerMSW::ms_pfnRasDeleteEntry = 0;
364RASVALIDATEENTRYNAME wxDialUpManagerMSW::ms_pfnRasValidateEntryName = 0;
365RASCONNECTIONNOTIFICATION wxDialUpManagerMSW::ms_pfnRasConnectionNotification = 0;
366
367int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus = -1;
368int wxDialUpManagerMSW::ms_isConnected = -1;
369wxDialUpManagerMSW *wxDialUpManagerMSW::ms_dialer = NULL;
370
371// ----------------------------------------------------------------------------
372// ctor and dtor: the dynamic linking happens here
373// ----------------------------------------------------------------------------
374
375// the static creator function is implemented here
376wxDialUpManager *wxDialUpManager::Create()
377{
378 return new wxDialUpManagerMSW;
379}
380
381#ifdef __VISUALC__
382 // warning about "'this' : used in base member initializer list" - so what?
383 #pragma warning(disable:4355)
384#endif // VC++
385
386wxDialUpManagerMSW::wxDialUpManagerMSW()
4522bb3e 387 : m_timerStatusPolling(this),
9a83f860 388 m_dllRas(wxT("RASAPI32"))
a0b4c98b
VZ
389{
390 // initialize our data
6bba111c 391 m_autoCheckLevel = 0;
a0b4c98b 392 m_hThread = 0;
97247d36 393 m_data = new wxRasThreadData;
a0b4c98b 394
4f89dbc4
RL
395 if ( !m_dllRas.IsLoaded() )
396 {
397 wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it."));
398 }
1c25d245 399 else if ( !ms_pfnRasDial )
a0b4c98b 400 {
4f89dbc4
RL
401 // resolve the functions we need
402
403 // this will contain the name of the function we failed to resolve
404 // if any at the end
405 const char *funcName = NULL;
406
407 // get the function from rasapi32.dll and abort if it's not found
408 #define RESOLVE_RAS_FUNCTION(type, name) \
9a83f860 409 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(wxT(#name)) \
4f89dbc4
RL
410 + gs_funcSuffix); \
411 if ( !ms_pfn##name ) \
412 { \
413 funcName = #name; \
414 goto exit; \
415 }
416
417 // a variant of above macro which doesn't abort if the function is
418 // not found in the DLL
419 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
9a83f860 420 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(wxT(#name)) \
4f89dbc4
RL
421 + gs_funcSuffix);
422
423 RESOLVE_RAS_FUNCTION(RASDIAL, RasDial);
424 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS, RasEnumConnections);
425 RESOLVE_RAS_FUNCTION(RASENUMENTRIES, RasEnumEntries);
426 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS, RasGetConnectStatus);
427 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING, RasGetErrorString);
428 RESOLVE_RAS_FUNCTION(RASHANGUP, RasHangUp);
429 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS, RasGetEntryDialParams);
430
431 // suppress error messages about missing (non essential) functions
a0b4c98b 432 {
4f89dbc4
RL
433 wxLogNull noLog;
434
435 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO, RasGetProjectionInfo);
436 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY, RasCreatePhonebookEntry);
437 RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY, RasEditPhonebookEntry);
438 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS, RasSetEntryDialParams);
439 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES, RasGetEntryProperties);
440 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES, RasSetEntryProperties);
441 RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY, RasRenameEntry);
442 RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY, RasDeleteEntry);
443 RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME, RasValidateEntryName);
444 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO, RasGetCountryInfo);
445 RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES, RasEnumDevices);
446 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION, RasConnectionNotification);
a0b4c98b 447 }
a0b4c98b 448
4f89dbc4
RL
449 // keep your preprocessor name space clean
450 #undef RESOLVE_RAS_FUNCTION
451 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
a0b4c98b
VZ
452
453exit:
4f89dbc4
RL
454 if ( funcName )
455 {
e6d4038a
VZ
456 wxLogError(_("The version of remote access service (RAS) installed "
457 "on this machine is too old, please upgrade (the "
458 "following required function is missing: %s)."),
459 funcName);
4f89dbc4
RL
460 m_dllRas.Unload();
461 return;
a0b4c98b
VZ
462 }
463 }
464
465 // enable auto check by default
466 EnableAutoCheckOnlineStatus(0);
467}
468
469wxDialUpManagerMSW::~wxDialUpManagerMSW()
470{
471 CleanUpThreadData();
a0b4c98b
VZ
472}
473
474// ----------------------------------------------------------------------------
475// helper functions
476// ----------------------------------------------------------------------------
477
478wxString wxDialUpManagerMSW::GetErrorString(DWORD error)
479{
480 wxChar buffer[512]; // this should be more than enough according to MS docs
481 DWORD dwRet = ms_pfnRasGetErrorString(error, buffer, WXSIZEOF(buffer));
482 switch ( dwRet )
483 {
484 case ERROR_INVALID_PARAMETER:
485 // this was a standard Win32 error probably
486 return wxString(wxSysErrorMsg(error));
487
488 default:
489 {
f6bcfd97
BP
490 wxLogSysError(dwRet,
491 _("Failed to retrieve text of RAS error message"));
a0b4c98b
VZ
492
493 wxString msg;
494 msg.Printf(_("unknown error (error code %08x)."), error);
495 return msg;
496 }
497
498 case 0:
499 // we want the error message to start from a lower case letter
907173e5 500 buffer[0] = (wxChar)wxTolower(buffer[0]);
a0b4c98b
VZ
501
502 return wxString(buffer);
503 }
504}
505
506HRASCONN wxDialUpManagerMSW::FindActiveConnection()
507{
508 // enumerate connections
509 DWORD cbBuf = sizeof(RASCONN);
510 LPRASCONN lpRasConn = (LPRASCONN)malloc(cbBuf);
511 if ( !lpRasConn )
512 {
513 // out of memory
514 return 0;
515 }
516
517 lpRasConn->dwSize = sizeof(RASCONN);
518
519 DWORD nConnections = 0;
520 DWORD dwRet = ERROR_BUFFER_TOO_SMALL;
521
522 while ( dwRet == ERROR_BUFFER_TOO_SMALL )
523 {
524 dwRet = ms_pfnRasEnumConnections(lpRasConn, &cbBuf, &nConnections);
525
526 if ( dwRet == ERROR_BUFFER_TOO_SMALL )
527 {
528 LPRASCONN lpRasConnOld = lpRasConn;
529 lpRasConn = (LPRASCONN)realloc(lpRasConn, cbBuf);
530 if ( !lpRasConn )
531 {
532 // out of memory
533 free(lpRasConnOld);
534
535 return 0;
536 }
537 }
538 else if ( dwRet == 0 )
539 {
540 // ok, success
541 break;
542 }
543 else
544 {
3103e8a9 545 // an error occurred
a0b4c98b 546 wxLogError(_("Cannot find active dialup connection: %s"),
5b09e9c2 547 GetErrorString(dwRet).c_str());
a0b4c98b
VZ
548 return 0;
549 }
550 }
551
552 HRASCONN hrasconn;
553
554 switch ( nConnections )
555 {
556 case 0:
557 // no connections
558 hrasconn = 0;
559 break;
560
561 default:
562 // more than 1 connection - we don't know what to do with this
563 // case, so give a warning but continue (taking the first
564 // connection) - the warning is really needed because this function
565 // is used, for example, to select the connection to hang up and so
566 // we may hang up the wrong connection here...
f6bcfd97 567 wxLogWarning(_("Several active dialup connections found, choosing one randomly."));
a0b4c98b
VZ
568 // fall through
569
570 case 1:
571 // exactly 1 connection, great
572 hrasconn = lpRasConn->hrasconn;
573 }
574
575 free(lpRasConn);
576
577 return hrasconn;
578}
579
580void wxDialUpManagerMSW::CleanUpThreadData()
581{
582 if ( m_hThread )
583 {
97247d36 584 if ( !SetEvent(m_data->hEventQuit) )
a0b4c98b 585 {
9a83f860 586 wxLogLastError(wxT("SetEvent(RasThreadQuit)"));
a0b4c98b 587 }
97247d36
VZ
588 else // sent quit request to the background thread
589 {
590 // the thread still needs m_data so we can't free it here, rather
591 // let the thread do it itself
592 m_data = NULL;
593 }
a0b4c98b
VZ
594
595 CloseHandle(m_hThread);
596
597 m_hThread = 0;
598 }
599
5276b0a5 600 wxDELETE(m_data);
a0b4c98b
VZ
601}
602
603// ----------------------------------------------------------------------------
604// connection status
605// ----------------------------------------------------------------------------
606
607void wxDialUpManagerMSW::CheckRasStatus()
608{
609 // use int, not bool to compare with -1
610 int isConnected = FindActiveConnection() != 0;
611 if ( isConnected != ms_isConnected )
612 {
613 if ( ms_isConnected != -1 )
614 {
615 // notify the program
616 NotifyApp(isConnected != 0);
617 }
618 // else: it's the first time we're called, just update the flag
619
620 ms_isConnected = isConnected;
621 }
622}
623
624void wxDialUpManagerMSW::NotifyApp(bool connected, bool fromOurselves) const
625{
626 wxDialUpEvent event(connected, fromOurselves);
627 (void)wxTheApp->ProcessEvent(event);
628}
629
630// this function is called whenever the status of any RAS connection on this
631// machine changes by RAS itself
632void wxDialUpManagerMSW::OnConnectStatusChange()
633{
634 // we know that status changed, but we don't know whether we're connected
635 // or not - so find it out
636 CheckRasStatus();
637}
638
639// this function is called by our callback which we give to RasDial() when
640// calling it asynchronously
641void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate,
642 DWORD dwError)
643{
644 if ( !GetDialer() )
645 {
646 // this probably means that CancelDialing() was called and we get
647 // "disconnected" notification
648 return;
649 }
650
651 // we're only interested in 2 events: connected and disconnected
652 if ( dwError )
653 {
654 wxLogError(_("Failed to establish dialup connection: %s"),
5b09e9c2 655 GetErrorString(dwError).c_str());
a0b4c98b
VZ
656
657 // we should still call RasHangUp() if we got a non 0 connection
658 if ( ms_hRasConnection )
659 {
660 ms_pfnRasHangUp(ms_hRasConnection);
661 ms_hRasConnection = 0;
662 }
663
664 ms_dialer = NULL;
665
d71cc120 666 NotifyApp(false /* !connected */, true /* we dialed ourselves */);
a0b4c98b
VZ
667 }
668 else if ( rasconnstate == RASCS_Connected )
669 {
d71cc120 670 ms_isConnected = true;
a0b4c98b
VZ
671 ms_dialer = NULL;
672
d71cc120 673 NotifyApp(true /* connected */, true /* we dialed ourselves */);
a0b4c98b
VZ
674 }
675}
676
677// ----------------------------------------------------------------------------
678// implementation of wxDialUpManager functions
679// ----------------------------------------------------------------------------
680
681bool wxDialUpManagerMSW::IsOk() const
682{
4f89dbc4 683 return m_dllRas.IsLoaded();
a0b4c98b
VZ
684}
685
2690830e
VZ
686size_t wxDialUpManagerMSW::GetISPNames(wxArrayString& names) const
687{
688 // fetch the entries
689 DWORD size = sizeof(RASENTRYNAME);
690 RASENTRYNAME *rasEntries = (RASENTRYNAME *)malloc(size);
691 rasEntries->dwSize = sizeof(RASENTRYNAME);
692
693 DWORD nEntries;
694 DWORD dwRet;
695 do
696 {
697 dwRet = ms_pfnRasEnumEntries
698 (
699 NULL, // reserved
700 NULL, // default phone book (or all)
701 rasEntries, // [out] buffer for the entries
702 &size, // [in/out] size of the buffer
703 &nEntries // [out] number of entries fetched
704 );
705
706 if ( dwRet == ERROR_BUFFER_TOO_SMALL )
707 {
708 // reallocate the buffer
fb9bea06
JS
709 void *n = realloc(rasEntries, size);
710 if (n == NULL)
711 {
712 free(rasEntries);
713 return 0;
714 }
715 rasEntries = (RASENTRYNAME *)n;
2690830e
VZ
716 }
717 else if ( dwRet != 0 )
718 {
719 // some other error - abort
5b09e9c2
VZ
720 wxLogError(_("Failed to get ISP names: %s"),
721 GetErrorString(dwRet).c_str());
2690830e
VZ
722
723 free(rasEntries);
724
725 return 0u;
726 }
727 }
728 while ( dwRet != 0 );
729
730 // process them
731 names.Empty();
732 for ( size_t n = 0; n < (size_t)nEntries; n++ )
733 {
734 names.Add(rasEntries[n].szEntryName);
735 }
736
737 free(rasEntries);
738
739 // return the number of entries
740 return names.GetCount();
741}
742
a0b4c98b
VZ
743bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
744 const wxString& username,
745 const wxString& password,
746 bool async)
747{
2690830e 748 // check preconditions
d71cc120 749 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
750
751 if ( ms_hRasConnection )
752 {
223d09f6 753 wxFAIL_MSG(wxT("there is already an active connection"));
a0b4c98b 754
d71cc120 755 return true;
a0b4c98b
VZ
756 }
757
2690830e
VZ
758 // get the default ISP if none given
759 wxString entryName(nameOfISP);
760 if ( !entryName )
761 {
762 wxArrayString names;
763 size_t count = GetISPNames(names);
764 switch ( count )
765 {
766 case 0:
767 // no known ISPs, abort
768 wxLogError(_("Failed to connect: no ISP to dial."));
769
d71cc120 770 return false;
2690830e
VZ
771
772 case 1:
773 // only one ISP, choose it
774 entryName = names[0u];
775 break;
776
777 default:
778 // several ISPs, let the user choose
779 {
780 wxString *strings = new wxString[count];
781 for ( size_t i = 0; i < count; i++ )
782 {
783 strings[i] = names[i];
784 }
785
786 entryName = wxGetSingleChoice
787 (
788 _("Choose ISP to dial"),
f6bcfd97 789 _("Please choose which ISP do you want to connect to"),
2690830e
VZ
790 count,
791 strings
792 );
793
794 delete [] strings;
795
796 if ( !entryName )
797 {
798 // cancelled by user
d71cc120 799 return false;
2690830e
VZ
800 }
801 }
802 }
803 }
804
a0b4c98b
VZ
805 RASDIALPARAMS rasDialParams;
806 rasDialParams.dwSize = sizeof(rasDialParams);
64accea5 807 wxStrlcpy(rasDialParams.szEntryName, entryName.c_str(), RAS_MaxEntryName);
2690830e
VZ
808
809 // do we have the username and password?
810 if ( !username || !password )
811 {
812 BOOL gotPassword;
813 DWORD dwRet = ms_pfnRasGetEntryDialParams
814 (
815 NULL, // default phonebook
816 &rasDialParams, // [in/out] the params of this entry
817 &gotPassword // [out] did we get password?
818 );
819
820 if ( dwRet != 0 )
821 {
822 wxLogError(_("Failed to connect: missing username/password."));
823
d71cc120 824 return false;
2690830e
VZ
825 }
826 }
4f89dbc4
RL
827 else
828 {
64accea5
VZ
829 wxStrlcpy(rasDialParams.szUserName, username.c_str(), UNLEN);
830 wxStrlcpy(rasDialParams.szPassword, password.c_str(), PWLEN);
4f89dbc4 831 }
2690830e 832
4f89dbc4 833 // default values for other fields
a0b4c98b
VZ
834 rasDialParams.szPhoneNumber[0] = '\0';
835 rasDialParams.szCallbackNumber[0] = '\0';
836 rasDialParams.szCallbackNumber[0] = '\0';
837
a0b4c98b
VZ
838 rasDialParams.szDomain[0] = '*';
839 rasDialParams.szDomain[1] = '\0';
840
841 // apparently, this is not really necessary - passing NULL instead of the
842 // phone book has the same effect
843#if 0
844 wxString phoneBook;
845 if ( wxGetOsVersion() == wxWINDOWS_NT )
846 {
847 // first get the length
848 UINT nLen = ::GetSystemDirectory(NULL, 0);
849 nLen++;
850
851 if ( !::GetSystemDirectory(phoneBook.GetWriteBuf(nLen), nLen) )
852 {
853 wxLogSysError(_("Cannot find the location of address book file"));
854 }
855
856 phoneBook.UngetWriteBuf();
857
858 // this is the default phone book
859 phoneBook << "\\ras\\rasphone.pbk";
860 }
861#endif // 0
862
863 // TODO may be we should disable auto check while async dialing is in
864 // progress?
865
866 ms_dialer = this;
867
868 DWORD dwRet = ms_pfnRasDial
869 (
1c25d245
VZ
870 NULL, // no extended features
871 NULL, // default phone book file (NT only)
a0b4c98b 872 &rasDialParams,
1c25d245
VZ
873 0, // use callback for notifications
874 async ? (void *)wxRasDialFunc // cast needed for gcc 3.1
875 : 0, // no notifications, sync operation
a0b4c98b
VZ
876 &ms_hRasConnection
877 );
878
879 if ( dwRet != 0 )
880 {
bf9b6266 881 // can't pass a wxWCharBuffer through ( ... )
32efa676 882 if ( async )
43b2d5e7 883 {
32efa676
VS
884 wxLogError(_("Failed to initiate dialup connection: %s"),
885 GetErrorString(dwRet).c_str());
43b2d5e7 886 }
32efa676 887 else
43b2d5e7 888 {
32efa676
VS
889 wxLogError(_("Failed to establish dialup connection: %s"),
890 GetErrorString(dwRet).c_str());
43b2d5e7 891 }
a0b4c98b
VZ
892
893 // we should still call RasHangUp() if we got a non 0 connection
894 if ( ms_hRasConnection )
895 {
896 ms_pfnRasHangUp(ms_hRasConnection);
897 ms_hRasConnection = 0;
898 }
899
900 ms_dialer = NULL;
901
d71cc120 902 return false;
a0b4c98b
VZ
903 }
904
905 // for async dialing, we're not yet connected
906 if ( !async )
907 {
d71cc120 908 ms_isConnected = true;
a0b4c98b
VZ
909 }
910
d71cc120 911 return true;
a0b4c98b
VZ
912}
913
914bool wxDialUpManagerMSW::IsDialing() const
915{
916 return GetDialer() != NULL;
917}
918
919bool wxDialUpManagerMSW::CancelDialing()
920{
921 if ( !GetDialer() )
922 {
923 // silently ignore
d71cc120 924 return false;
a0b4c98b
VZ
925 }
926
223d09f6 927 wxASSERT_MSG( ms_hRasConnection, wxT("dialing but no connection?") );
a0b4c98b
VZ
928
929 ms_dialer = NULL;
930
931 return HangUp();
932}
933
934bool wxDialUpManagerMSW::HangUp()
935{
d71cc120 936 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
937
938 // we may terminate either the connection we initiated or another one which
939 // is active now
940 HRASCONN hRasConn;
941 if ( ms_hRasConnection )
942 {
943 hRasConn = ms_hRasConnection;
944
945 ms_hRasConnection = 0;
946 }
947 else
948 {
949 hRasConn = FindActiveConnection();
950 }
951
952 if ( !hRasConn )
953 {
954 wxLogError(_("Cannot hang up - no active dialup connection."));
955
d71cc120 956 return false;
a0b4c98b
VZ
957 }
958
fbd3c46d
VZ
959 // note that it's not an error if the connection had been already
960 // terminated
961 const DWORD dwRet = ms_pfnRasHangUp(hRasConn);
962 if ( dwRet != 0 && dwRet != ERROR_NO_CONNECTION )
a0b4c98b
VZ
963 {
964 wxLogError(_("Failed to terminate the dialup connection: %s"),
5b09e9c2 965 GetErrorString(dwRet).c_str());
a0b4c98b
VZ
966 }
967
d71cc120 968 ms_isConnected = false;
a0b4c98b 969
d71cc120 970 return true;
a0b4c98b
VZ
971}
972
2690830e
VZ
973bool wxDialUpManagerMSW::IsAlwaysOnline() const
974{
19caf229 975 // assume no permanent connection by default
d71cc120 976 bool isAlwaysOnline = false;
2690830e 977
19caf229 978 // try to use WinInet functions
4f89dbc4
RL
979
980 // NB: we could probably use wxDynamicLibrary here just as well,
981 // but we allow multiple instances of wxDialUpManagerMSW so
982 // we might as well use the ref counted version here too.
983
9a83f860 984 wxDynamicLibrary hDll(wxT("WININET"));
4f89dbc4 985 if ( hDll.IsLoaded() )
2690830e 986 {
5a56be28 987 typedef BOOL (WINAPI *INTERNETGETCONNECTEDSTATE)(LPDWORD, DWORD);
2690830e
VZ
988 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState;
989
990 #define RESOLVE_FUNCTION(type, name) \
9a83f860 991 pfn##name = (type)hDll.GetSymbol(wxT(#name))
2690830e
VZ
992
993 RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE, InternetGetConnectedState);
994
995 if ( pfnInternetGetConnectedState )
996 {
997 DWORD flags = 0;
998 if ( pfnInternetGetConnectedState(&flags, 0 /* reserved */) )
999 {
1000 // there is some connection to the net, see of which type
19caf229
VZ
1001 isAlwaysOnline = (flags & (INTERNET_CONNECTION_LAN |
1002 INTERNET_CONNECTION_PROXY)) != 0;
2690830e 1003 }
19caf229 1004 //else: no Internet connection at all
2690830e
VZ
1005 }
1006 }
1007
19caf229 1008 return isAlwaysOnline;
2690830e
VZ
1009}
1010
a0b4c98b
VZ
1011bool wxDialUpManagerMSW::IsOnline() const
1012{
d71cc120 1013 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
a0b4c98b 1014
90e9494a
VZ
1015 if ( IsAlwaysOnline() )
1016 {
1017 // always => now
1018 return true;
1019 }
1020
a0b4c98b
VZ
1021 if ( ms_userSpecifiedOnlineStatus != -1 )
1022 {
1023 // user specified flag overrides our logic
1024 return ms_userSpecifiedOnlineStatus != 0;
1025 }
1026 else
1027 {
d71cc120 1028 // return true if there is at least one active connection
a0b4c98b
VZ
1029 return FindActiveConnection() != 0;
1030 }
1031}
1032
1033void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline)
1034{
223d09f6 1035 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
1036
1037 ms_userSpecifiedOnlineStatus = isOnline;
1038}
1039
1040bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
1041{
d71cc120 1042 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
a0b4c98b 1043
6bba111c
VZ
1044 if ( m_autoCheckLevel++ )
1045 {
1046 // already checking
d71cc120 1047 return true;
6bba111c
VZ
1048 }
1049
a0b4c98b
VZ
1050 bool ok = ms_pfnRasConnectionNotification != 0;
1051
1052 if ( ok )
1053 {
1054 // we're running under NT 4.0, Windows 98 or later and can use
1055 // RasConnectionNotification() to be notified by a secondary thread
1056
1057 // first, see if we don't have this thread already running
1058 if ( m_hThread != 0 )
1059 {
6bba111c 1060 if ( ::ResumeThread(m_hThread) != (DWORD)-1 )
d71cc120 1061 return true;
a0b4c98b 1062
6bba111c
VZ
1063 // we're leaving a zombie thread... but what else can we do?
1064 wxLogLastError(wxT("ResumeThread(RasThread)"));
a0b4c98b 1065
d71cc120 1066 ok = false;
a0b4c98b
VZ
1067 }
1068 }
1069
1070 // create all the stuff we need to be notified about RAS connection
1071 // status change
1072
1073 if ( ok )
1074 {
1075 // first create an event to wait on
d71cc120 1076 m_data->hEventRas = ::CreateEvent
97247d36 1077 (
a0b4c98b 1078 NULL, // security attribute (default)
97247d36 1079 FALSE, // manual reset (no, it is automatic)
a0b4c98b
VZ
1080 FALSE, // initial state (not signaled)
1081 NULL // name (no)
97247d36
VZ
1082 );
1083 if ( !m_data->hEventRas )
a0b4c98b 1084 {
f6bcfd97 1085 wxLogLastError(wxT("CreateEvent(RasStatus)"));
a0b4c98b 1086
d71cc120 1087 ok = false;
a0b4c98b
VZ
1088 }
1089 }
1090
1091 if ( ok )
1092 {
97247d36
VZ
1093 // create the event we use to quit the thread: using a manual event
1094 // here avoids problems with missing the event if wxDialUpManagerMSW
1095 // is created and destroyed immediately, before wxRasStatusWindowProc
1096 // starts waiting on the event
d71cc120 1097 m_data->hEventQuit = ::CreateEvent
97247d36
VZ
1098 (
1099 NULL, // default security
1100 TRUE, // manual event
1101 FALSE, // initially non signalled
1102 NULL // nameless
1103 );
1104 if ( !m_data->hEventQuit )
a0b4c98b 1105 {
f6bcfd97 1106 wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
a0b4c98b
VZ
1107
1108 CleanUpThreadData();
1109
d71cc120 1110 ok = false;
a0b4c98b
VZ
1111 }
1112 }
1113
2690830e 1114 if ( ok && !ms_hwndRas )
a0b4c98b
VZ
1115 {
1116 // create a hidden window to receive notification about connections
1117 // status change
8563c6f1
VZ
1118 ms_hwndRas = wxCreateHiddenWindow
1119 (
1120 &gs_classForDialUpWindow,
1121 wxMSWDIALUP_WNDCLASSNAME,
1122 wxRasStatusWindowProc
1123 );
2690830e 1124 if ( !ms_hwndRas )
a0b4c98b 1125 {
f6bcfd97 1126 wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
a0b4c98b
VZ
1127
1128 CleanUpThreadData();
1129
d71cc120 1130 ok = false;
a0b4c98b 1131 }
a0b4c98b
VZ
1132 }
1133
97247d36 1134 m_data->hWnd = ms_hwndRas;
2690830e 1135
a0b4c98b
VZ
1136 if ( ok )
1137 {
1138 // start the secondary thread
97247d36 1139 m_data->dialUpManager = this;
a0b4c98b
VZ
1140
1141 DWORD tid;
1142 m_hThread = CreateThread
1143 (
1144 NULL,
1145 0,
1146 (LPTHREAD_START_ROUTINE)wxRasMonitorThread,
97247d36 1147 (void *)m_data,
a0b4c98b
VZ
1148 0,
1149 &tid
1150 );
1151
1152 if ( !m_hThread )
1153 {
f6bcfd97 1154 wxLogLastError(wxT("CreateThread(RasStatusThread)"));
a0b4c98b
VZ
1155
1156 CleanUpThreadData();
1157 }
1158 }
1159
1160 if ( ok )
1161 {
1162 // start receiving RAS notifications
1163 DWORD dwRet = ms_pfnRasConnectionNotification
1164 (
1165 (HRASCONN)INVALID_HANDLE_VALUE,
97247d36 1166 m_data->hEventRas,
a0b4c98b
VZ
1167 3 /* RASCN_Connection | RASCN_Disconnection */
1168 );
1169
1170 if ( dwRet != 0 )
1171 {
223d09f6 1172 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
5b09e9c2 1173 GetErrorString(dwRet).c_str());
a0b4c98b
VZ
1174
1175 CleanUpThreadData();
1176 }
1177 else
1178 {
d71cc120 1179 return true;
a0b4c98b
VZ
1180 }
1181 }
1182
1183 // we're running under Windows 95 and have to poll ourselves
1184 // (or, alternatively, the code above for NT/98 failed)
1185 m_timerStatusPolling.Stop();
1186 if ( nSeconds == 0 )
1187 {
1188 // default value
1189 nSeconds = 60;
1190 }
1191 m_timerStatusPolling.Start(nSeconds * 1000);
1192
d71cc120 1193 return true;
a0b4c98b
VZ
1194}
1195
1196void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
1197{
223d09f6 1198 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
a0b4c98b 1199
8d7eaf91 1200 if ( --m_autoCheckLevel != 0 )
6bba111c
VZ
1201 {
1202 // still checking
1203 return;
1204 }
1205
a0b4c98b
VZ
1206 if ( m_hThread )
1207 {
1208 // we have running secondary thread, it's just enough to suspend it
1209 if ( SuspendThread(m_hThread) == (DWORD)-1 )
1210 {
f6bcfd97 1211 wxLogLastError(wxT("SuspendThread(RasThread)"));
a0b4c98b
VZ
1212 }
1213 }
1214 else
1215 {
1216 // even simpler - just stop the timer
1217 m_timerStatusPolling.Stop();
1218 }
1219}
1220
1221// ----------------------------------------------------------------------------
1222// stubs which don't do anything in MSW version
1223// ----------------------------------------------------------------------------
1224
1225void wxDialUpManagerMSW::SetWellKnownHost(const wxString& WXUNUSED(hostname),
1226 int WXUNUSED(port))
1227{
223d09f6 1228 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
1229
1230 // nothing to do - we don't use this
1231}
1232
1233void wxDialUpManagerMSW::SetConnectCommand(const wxString& WXUNUSED(dial),
1234 const wxString& WXUNUSED(hangup))
1235{
223d09f6 1236 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
1237
1238 // nothing to do - we don't use this
1239}
1240
1241// ----------------------------------------------------------------------------
1242// callbacks
1243// ----------------------------------------------------------------------------
1244
1245static DWORD wxRasMonitorThread(wxRasThreadData *data)
1246{
1247 HANDLE handles[2];
1248 handles[0] = data->hEventRas;
1249 handles[1] = data->hEventQuit;
1250
d71cc120 1251 bool cont = true;
a0b4c98b
VZ
1252 while ( cont )
1253 {
d71cc120 1254 DWORD dwRet = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
a0b4c98b
VZ
1255
1256 switch ( dwRet )
1257 {
1258 case WAIT_OBJECT_0:
1259 // RAS connection status changed
1260 SendMessage(data->hWnd, wxWM_RAS_STATUS_CHANGED,
1261 0, (LPARAM)data);
1262 break;
1263
1264 case WAIT_OBJECT_0 + 1:
d71cc120 1265 cont = false;
a0b4c98b
VZ
1266 break;
1267
97247d36 1268 default:
9a83f860 1269 wxFAIL_MSG( wxT("unexpected return of WaitForMultipleObjects()") );
97247d36
VZ
1270 // fall through
1271
a0b4c98b 1272 case WAIT_FAILED:
97247d36
VZ
1273 // using wxLogLastError() from here is dangerous: we risk to
1274 // deadlock the main thread if wxLog sends output to GUI
1275 DWORD err = GetLastError();
141f4958
WS
1276 wxMessageOutputDebug dbg;
1277 dbg.Printf
97247d36
VZ
1278 (
1279 wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"),
1280 err,
1281 wxSysErrorMsg(err)
1282 );
97247d36
VZ
1283
1284 // no sense in continuing, who knows if the handles we're
1285 // waiting for even exist yet...
1286 return (DWORD)-1;
a0b4c98b
VZ
1287 }
1288 }
1289
97247d36
VZ
1290 // we don't need it any more now and if this thread ran, it is our
1291 // responsability to free the data
1292 delete data;
1293
a0b4c98b
VZ
1294 return 0;
1295}
1296
1297static LRESULT APIENTRY wxRasStatusWindowProc(HWND hWnd, UINT message,
1298 WPARAM wParam, LPARAM lParam)
1299{
cd6af1cb 1300 switch ( message )
a0b4c98b 1301 {
cd6af1cb
VZ
1302 case wxWM_RAS_STATUS_CHANGED:
1303 {
1304 wxRasThreadData *data = (wxRasThreadData *)lParam;
1305 data->dialUpManager->OnConnectStatusChange();
1306 }
1307 break;
2690830e 1308
cd6af1cb
VZ
1309 case wxWM_RAS_DIALING_PROGRESS:
1310 {
1311 wxDialUpManagerMSW *dialMan = wxDialUpManagerMSW::GetDialer();
1312
1313 dialMan->OnDialProgress((RASCONNSTATE)wParam, lParam);
1314 }
1315 break;
1316
1317 default:
1318 return ::DefWindowProc(hWnd, message, wParam, lParam);
2690830e 1319 }
a0b4c98b
VZ
1320
1321 return 0;
1322}
1323
2eb10e2a 1324static void WINAPI wxRasDialFunc(UINT WXUNUSED(unMsg),
a0b4c98b
VZ
1325 RASCONNSTATE rasconnstate,
1326 DWORD dwError)
1327{
1328 wxDialUpManagerMSW *dialUpManager = wxDialUpManagerMSW::GetDialer();
1329
223d09f6 1330 wxCHECK_RET( dialUpManager, wxT("who started to dial then?") );
a0b4c98b 1331
2a1f999f 1332 SendMessage(wxDialUpManagerMSW::GetRasWindow(), wxWM_RAS_DIALING_PROGRESS,
2690830e 1333 rasconnstate, dwError);
a0b4c98b
VZ
1334}
1335
1c25d245
VZ
1336#endif // __BORLANDC__
1337
a0b4c98b 1338#endif // wxUSE_DIALUP_MANAGER