]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dialup.cpp
Fix wxListCtrl::EndEditLabel() which simply didn't work.
[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
97247d36 600 if ( m_data )
a0b4c98b 601 {
97247d36
VZ
602 delete m_data;
603 m_data = NULL;
a0b4c98b
VZ
604 }
605}
606
607// ----------------------------------------------------------------------------
608// connection status
609// ----------------------------------------------------------------------------
610
611void wxDialUpManagerMSW::CheckRasStatus()
612{
613 // use int, not bool to compare with -1
614 int isConnected = FindActiveConnection() != 0;
615 if ( isConnected != ms_isConnected )
616 {
617 if ( ms_isConnected != -1 )
618 {
619 // notify the program
620 NotifyApp(isConnected != 0);
621 }
622 // else: it's the first time we're called, just update the flag
623
624 ms_isConnected = isConnected;
625 }
626}
627
628void wxDialUpManagerMSW::NotifyApp(bool connected, bool fromOurselves) const
629{
630 wxDialUpEvent event(connected, fromOurselves);
631 (void)wxTheApp->ProcessEvent(event);
632}
633
634// this function is called whenever the status of any RAS connection on this
635// machine changes by RAS itself
636void wxDialUpManagerMSW::OnConnectStatusChange()
637{
638 // we know that status changed, but we don't know whether we're connected
639 // or not - so find it out
640 CheckRasStatus();
641}
642
643// this function is called by our callback which we give to RasDial() when
644// calling it asynchronously
645void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate,
646 DWORD dwError)
647{
648 if ( !GetDialer() )
649 {
650 // this probably means that CancelDialing() was called and we get
651 // "disconnected" notification
652 return;
653 }
654
655 // we're only interested in 2 events: connected and disconnected
656 if ( dwError )
657 {
658 wxLogError(_("Failed to establish dialup connection: %s"),
5b09e9c2 659 GetErrorString(dwError).c_str());
a0b4c98b
VZ
660
661 // we should still call RasHangUp() if we got a non 0 connection
662 if ( ms_hRasConnection )
663 {
664 ms_pfnRasHangUp(ms_hRasConnection);
665 ms_hRasConnection = 0;
666 }
667
668 ms_dialer = NULL;
669
d71cc120 670 NotifyApp(false /* !connected */, true /* we dialed ourselves */);
a0b4c98b
VZ
671 }
672 else if ( rasconnstate == RASCS_Connected )
673 {
d71cc120 674 ms_isConnected = true;
a0b4c98b
VZ
675 ms_dialer = NULL;
676
d71cc120 677 NotifyApp(true /* connected */, true /* we dialed ourselves */);
a0b4c98b
VZ
678 }
679}
680
681// ----------------------------------------------------------------------------
682// implementation of wxDialUpManager functions
683// ----------------------------------------------------------------------------
684
685bool wxDialUpManagerMSW::IsOk() const
686{
4f89dbc4 687 return m_dllRas.IsLoaded();
a0b4c98b
VZ
688}
689
2690830e
VZ
690size_t wxDialUpManagerMSW::GetISPNames(wxArrayString& names) const
691{
692 // fetch the entries
693 DWORD size = sizeof(RASENTRYNAME);
694 RASENTRYNAME *rasEntries = (RASENTRYNAME *)malloc(size);
695 rasEntries->dwSize = sizeof(RASENTRYNAME);
696
697 DWORD nEntries;
698 DWORD dwRet;
699 do
700 {
701 dwRet = ms_pfnRasEnumEntries
702 (
703 NULL, // reserved
704 NULL, // default phone book (or all)
705 rasEntries, // [out] buffer for the entries
706 &size, // [in/out] size of the buffer
707 &nEntries // [out] number of entries fetched
708 );
709
710 if ( dwRet == ERROR_BUFFER_TOO_SMALL )
711 {
712 // reallocate the buffer
fb9bea06
JS
713 void *n = realloc(rasEntries, size);
714 if (n == NULL)
715 {
716 free(rasEntries);
717 return 0;
718 }
719 rasEntries = (RASENTRYNAME *)n;
2690830e
VZ
720 }
721 else if ( dwRet != 0 )
722 {
723 // some other error - abort
5b09e9c2
VZ
724 wxLogError(_("Failed to get ISP names: %s"),
725 GetErrorString(dwRet).c_str());
2690830e
VZ
726
727 free(rasEntries);
728
729 return 0u;
730 }
731 }
732 while ( dwRet != 0 );
733
734 // process them
735 names.Empty();
736 for ( size_t n = 0; n < (size_t)nEntries; n++ )
737 {
738 names.Add(rasEntries[n].szEntryName);
739 }
740
741 free(rasEntries);
742
743 // return the number of entries
744 return names.GetCount();
745}
746
a0b4c98b
VZ
747bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
748 const wxString& username,
749 const wxString& password,
750 bool async)
751{
2690830e 752 // check preconditions
d71cc120 753 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
754
755 if ( ms_hRasConnection )
756 {
223d09f6 757 wxFAIL_MSG(wxT("there is already an active connection"));
a0b4c98b 758
d71cc120 759 return true;
a0b4c98b
VZ
760 }
761
2690830e
VZ
762 // get the default ISP if none given
763 wxString entryName(nameOfISP);
764 if ( !entryName )
765 {
766 wxArrayString names;
767 size_t count = GetISPNames(names);
768 switch ( count )
769 {
770 case 0:
771 // no known ISPs, abort
772 wxLogError(_("Failed to connect: no ISP to dial."));
773
d71cc120 774 return false;
2690830e
VZ
775
776 case 1:
777 // only one ISP, choose it
778 entryName = names[0u];
779 break;
780
781 default:
782 // several ISPs, let the user choose
783 {
784 wxString *strings = new wxString[count];
785 for ( size_t i = 0; i < count; i++ )
786 {
787 strings[i] = names[i];
788 }
789
790 entryName = wxGetSingleChoice
791 (
792 _("Choose ISP to dial"),
f6bcfd97 793 _("Please choose which ISP do you want to connect to"),
2690830e
VZ
794 count,
795 strings
796 );
797
798 delete [] strings;
799
800 if ( !entryName )
801 {
802 // cancelled by user
d71cc120 803 return false;
2690830e
VZ
804 }
805 }
806 }
807 }
808
a0b4c98b
VZ
809 RASDIALPARAMS rasDialParams;
810 rasDialParams.dwSize = sizeof(rasDialParams);
64accea5 811 wxStrlcpy(rasDialParams.szEntryName, entryName.c_str(), RAS_MaxEntryName);
2690830e
VZ
812
813 // do we have the username and password?
814 if ( !username || !password )
815 {
816 BOOL gotPassword;
817 DWORD dwRet = ms_pfnRasGetEntryDialParams
818 (
819 NULL, // default phonebook
820 &rasDialParams, // [in/out] the params of this entry
821 &gotPassword // [out] did we get password?
822 );
823
824 if ( dwRet != 0 )
825 {
826 wxLogError(_("Failed to connect: missing username/password."));
827
d71cc120 828 return false;
2690830e
VZ
829 }
830 }
4f89dbc4
RL
831 else
832 {
64accea5
VZ
833 wxStrlcpy(rasDialParams.szUserName, username.c_str(), UNLEN);
834 wxStrlcpy(rasDialParams.szPassword, password.c_str(), PWLEN);
4f89dbc4 835 }
2690830e 836
4f89dbc4 837 // default values for other fields
a0b4c98b
VZ
838 rasDialParams.szPhoneNumber[0] = '\0';
839 rasDialParams.szCallbackNumber[0] = '\0';
840 rasDialParams.szCallbackNumber[0] = '\0';
841
a0b4c98b
VZ
842 rasDialParams.szDomain[0] = '*';
843 rasDialParams.szDomain[1] = '\0';
844
845 // apparently, this is not really necessary - passing NULL instead of the
846 // phone book has the same effect
847#if 0
848 wxString phoneBook;
849 if ( wxGetOsVersion() == wxWINDOWS_NT )
850 {
851 // first get the length
852 UINT nLen = ::GetSystemDirectory(NULL, 0);
853 nLen++;
854
855 if ( !::GetSystemDirectory(phoneBook.GetWriteBuf(nLen), nLen) )
856 {
857 wxLogSysError(_("Cannot find the location of address book file"));
858 }
859
860 phoneBook.UngetWriteBuf();
861
862 // this is the default phone book
863 phoneBook << "\\ras\\rasphone.pbk";
864 }
865#endif // 0
866
867 // TODO may be we should disable auto check while async dialing is in
868 // progress?
869
870 ms_dialer = this;
871
872 DWORD dwRet = ms_pfnRasDial
873 (
1c25d245
VZ
874 NULL, // no extended features
875 NULL, // default phone book file (NT only)
a0b4c98b 876 &rasDialParams,
1c25d245
VZ
877 0, // use callback for notifications
878 async ? (void *)wxRasDialFunc // cast needed for gcc 3.1
879 : 0, // no notifications, sync operation
a0b4c98b
VZ
880 &ms_hRasConnection
881 );
882
883 if ( dwRet != 0 )
884 {
bf9b6266 885 // can't pass a wxWCharBuffer through ( ... )
32efa676 886 if ( async )
43b2d5e7 887 {
32efa676
VS
888 wxLogError(_("Failed to initiate dialup connection: %s"),
889 GetErrorString(dwRet).c_str());
43b2d5e7 890 }
32efa676 891 else
43b2d5e7 892 {
32efa676
VS
893 wxLogError(_("Failed to establish dialup connection: %s"),
894 GetErrorString(dwRet).c_str());
43b2d5e7 895 }
a0b4c98b
VZ
896
897 // we should still call RasHangUp() if we got a non 0 connection
898 if ( ms_hRasConnection )
899 {
900 ms_pfnRasHangUp(ms_hRasConnection);
901 ms_hRasConnection = 0;
902 }
903
904 ms_dialer = NULL;
905
d71cc120 906 return false;
a0b4c98b
VZ
907 }
908
909 // for async dialing, we're not yet connected
910 if ( !async )
911 {
d71cc120 912 ms_isConnected = true;
a0b4c98b
VZ
913 }
914
d71cc120 915 return true;
a0b4c98b
VZ
916}
917
918bool wxDialUpManagerMSW::IsDialing() const
919{
920 return GetDialer() != NULL;
921}
922
923bool wxDialUpManagerMSW::CancelDialing()
924{
925 if ( !GetDialer() )
926 {
927 // silently ignore
d71cc120 928 return false;
a0b4c98b
VZ
929 }
930
223d09f6 931 wxASSERT_MSG( ms_hRasConnection, wxT("dialing but no connection?") );
a0b4c98b
VZ
932
933 ms_dialer = NULL;
934
935 return HangUp();
936}
937
938bool wxDialUpManagerMSW::HangUp()
939{
d71cc120 940 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
941
942 // we may terminate either the connection we initiated or another one which
943 // is active now
944 HRASCONN hRasConn;
945 if ( ms_hRasConnection )
946 {
947 hRasConn = ms_hRasConnection;
948
949 ms_hRasConnection = 0;
950 }
951 else
952 {
953 hRasConn = FindActiveConnection();
954 }
955
956 if ( !hRasConn )
957 {
958 wxLogError(_("Cannot hang up - no active dialup connection."));
959
d71cc120 960 return false;
a0b4c98b
VZ
961 }
962
fbd3c46d
VZ
963 // note that it's not an error if the connection had been already
964 // terminated
965 const DWORD dwRet = ms_pfnRasHangUp(hRasConn);
966 if ( dwRet != 0 && dwRet != ERROR_NO_CONNECTION )
a0b4c98b
VZ
967 {
968 wxLogError(_("Failed to terminate the dialup connection: %s"),
5b09e9c2 969 GetErrorString(dwRet).c_str());
a0b4c98b
VZ
970 }
971
d71cc120 972 ms_isConnected = false;
a0b4c98b 973
d71cc120 974 return true;
a0b4c98b
VZ
975}
976
2690830e
VZ
977bool wxDialUpManagerMSW::IsAlwaysOnline() const
978{
19caf229 979 // assume no permanent connection by default
d71cc120 980 bool isAlwaysOnline = false;
2690830e 981
19caf229 982 // try to use WinInet functions
4f89dbc4
RL
983
984 // NB: we could probably use wxDynamicLibrary here just as well,
985 // but we allow multiple instances of wxDialUpManagerMSW so
986 // we might as well use the ref counted version here too.
987
9a83f860 988 wxDynamicLibrary hDll(wxT("WININET"));
4f89dbc4 989 if ( hDll.IsLoaded() )
2690830e 990 {
5a56be28 991 typedef BOOL (WINAPI *INTERNETGETCONNECTEDSTATE)(LPDWORD, DWORD);
2690830e
VZ
992 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState;
993
994 #define RESOLVE_FUNCTION(type, name) \
9a83f860 995 pfn##name = (type)hDll.GetSymbol(wxT(#name))
2690830e
VZ
996
997 RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE, InternetGetConnectedState);
998
999 if ( pfnInternetGetConnectedState )
1000 {
1001 DWORD flags = 0;
1002 if ( pfnInternetGetConnectedState(&flags, 0 /* reserved */) )
1003 {
1004 // there is some connection to the net, see of which type
19caf229
VZ
1005 isAlwaysOnline = (flags & (INTERNET_CONNECTION_LAN |
1006 INTERNET_CONNECTION_PROXY)) != 0;
2690830e 1007 }
19caf229 1008 //else: no Internet connection at all
2690830e
VZ
1009 }
1010 }
1011
19caf229 1012 return isAlwaysOnline;
2690830e
VZ
1013}
1014
a0b4c98b
VZ
1015bool wxDialUpManagerMSW::IsOnline() const
1016{
d71cc120 1017 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
a0b4c98b 1018
90e9494a
VZ
1019 if ( IsAlwaysOnline() )
1020 {
1021 // always => now
1022 return true;
1023 }
1024
a0b4c98b
VZ
1025 if ( ms_userSpecifiedOnlineStatus != -1 )
1026 {
1027 // user specified flag overrides our logic
1028 return ms_userSpecifiedOnlineStatus != 0;
1029 }
1030 else
1031 {
d71cc120 1032 // return true if there is at least one active connection
a0b4c98b
VZ
1033 return FindActiveConnection() != 0;
1034 }
1035}
1036
1037void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline)
1038{
223d09f6 1039 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
1040
1041 ms_userSpecifiedOnlineStatus = isOnline;
1042}
1043
1044bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
1045{
d71cc120 1046 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
a0b4c98b 1047
6bba111c
VZ
1048 if ( m_autoCheckLevel++ )
1049 {
1050 // already checking
d71cc120 1051 return true;
6bba111c
VZ
1052 }
1053
a0b4c98b
VZ
1054 bool ok = ms_pfnRasConnectionNotification != 0;
1055
1056 if ( ok )
1057 {
1058 // we're running under NT 4.0, Windows 98 or later and can use
1059 // RasConnectionNotification() to be notified by a secondary thread
1060
1061 // first, see if we don't have this thread already running
1062 if ( m_hThread != 0 )
1063 {
6bba111c 1064 if ( ::ResumeThread(m_hThread) != (DWORD)-1 )
d71cc120 1065 return true;
a0b4c98b 1066
6bba111c
VZ
1067 // we're leaving a zombie thread... but what else can we do?
1068 wxLogLastError(wxT("ResumeThread(RasThread)"));
a0b4c98b 1069
d71cc120 1070 ok = false;
a0b4c98b
VZ
1071 }
1072 }
1073
1074 // create all the stuff we need to be notified about RAS connection
1075 // status change
1076
1077 if ( ok )
1078 {
1079 // first create an event to wait on
d71cc120 1080 m_data->hEventRas = ::CreateEvent
97247d36 1081 (
a0b4c98b 1082 NULL, // security attribute (default)
97247d36 1083 FALSE, // manual reset (no, it is automatic)
a0b4c98b
VZ
1084 FALSE, // initial state (not signaled)
1085 NULL // name (no)
97247d36
VZ
1086 );
1087 if ( !m_data->hEventRas )
a0b4c98b 1088 {
f6bcfd97 1089 wxLogLastError(wxT("CreateEvent(RasStatus)"));
a0b4c98b 1090
d71cc120 1091 ok = false;
a0b4c98b
VZ
1092 }
1093 }
1094
1095 if ( ok )
1096 {
97247d36
VZ
1097 // create the event we use to quit the thread: using a manual event
1098 // here avoids problems with missing the event if wxDialUpManagerMSW
1099 // is created and destroyed immediately, before wxRasStatusWindowProc
1100 // starts waiting on the event
d71cc120 1101 m_data->hEventQuit = ::CreateEvent
97247d36
VZ
1102 (
1103 NULL, // default security
1104 TRUE, // manual event
1105 FALSE, // initially non signalled
1106 NULL // nameless
1107 );
1108 if ( !m_data->hEventQuit )
a0b4c98b 1109 {
f6bcfd97 1110 wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
a0b4c98b
VZ
1111
1112 CleanUpThreadData();
1113
d71cc120 1114 ok = false;
a0b4c98b
VZ
1115 }
1116 }
1117
2690830e 1118 if ( ok && !ms_hwndRas )
a0b4c98b
VZ
1119 {
1120 // create a hidden window to receive notification about connections
1121 // status change
8563c6f1
VZ
1122 ms_hwndRas = wxCreateHiddenWindow
1123 (
1124 &gs_classForDialUpWindow,
1125 wxMSWDIALUP_WNDCLASSNAME,
1126 wxRasStatusWindowProc
1127 );
2690830e 1128 if ( !ms_hwndRas )
a0b4c98b 1129 {
f6bcfd97 1130 wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
a0b4c98b
VZ
1131
1132 CleanUpThreadData();
1133
d71cc120 1134 ok = false;
a0b4c98b 1135 }
a0b4c98b
VZ
1136 }
1137
97247d36 1138 m_data->hWnd = ms_hwndRas;
2690830e 1139
a0b4c98b
VZ
1140 if ( ok )
1141 {
1142 // start the secondary thread
97247d36 1143 m_data->dialUpManager = this;
a0b4c98b
VZ
1144
1145 DWORD tid;
1146 m_hThread = CreateThread
1147 (
1148 NULL,
1149 0,
1150 (LPTHREAD_START_ROUTINE)wxRasMonitorThread,
97247d36 1151 (void *)m_data,
a0b4c98b
VZ
1152 0,
1153 &tid
1154 );
1155
1156 if ( !m_hThread )
1157 {
f6bcfd97 1158 wxLogLastError(wxT("CreateThread(RasStatusThread)"));
a0b4c98b
VZ
1159
1160 CleanUpThreadData();
1161 }
1162 }
1163
1164 if ( ok )
1165 {
1166 // start receiving RAS notifications
1167 DWORD dwRet = ms_pfnRasConnectionNotification
1168 (
1169 (HRASCONN)INVALID_HANDLE_VALUE,
97247d36 1170 m_data->hEventRas,
a0b4c98b
VZ
1171 3 /* RASCN_Connection | RASCN_Disconnection */
1172 );
1173
1174 if ( dwRet != 0 )
1175 {
223d09f6 1176 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
5b09e9c2 1177 GetErrorString(dwRet).c_str());
a0b4c98b
VZ
1178
1179 CleanUpThreadData();
1180 }
1181 else
1182 {
d71cc120 1183 return true;
a0b4c98b
VZ
1184 }
1185 }
1186
1187 // we're running under Windows 95 and have to poll ourselves
1188 // (or, alternatively, the code above for NT/98 failed)
1189 m_timerStatusPolling.Stop();
1190 if ( nSeconds == 0 )
1191 {
1192 // default value
1193 nSeconds = 60;
1194 }
1195 m_timerStatusPolling.Start(nSeconds * 1000);
1196
d71cc120 1197 return true;
a0b4c98b
VZ
1198}
1199
1200void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
1201{
223d09f6 1202 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
a0b4c98b 1203
8d7eaf91 1204 if ( --m_autoCheckLevel != 0 )
6bba111c
VZ
1205 {
1206 // still checking
1207 return;
1208 }
1209
a0b4c98b
VZ
1210 if ( m_hThread )
1211 {
1212 // we have running secondary thread, it's just enough to suspend it
1213 if ( SuspendThread(m_hThread) == (DWORD)-1 )
1214 {
f6bcfd97 1215 wxLogLastError(wxT("SuspendThread(RasThread)"));
a0b4c98b
VZ
1216 }
1217 }
1218 else
1219 {
1220 // even simpler - just stop the timer
1221 m_timerStatusPolling.Stop();
1222 }
1223}
1224
1225// ----------------------------------------------------------------------------
1226// stubs which don't do anything in MSW version
1227// ----------------------------------------------------------------------------
1228
1229void wxDialUpManagerMSW::SetWellKnownHost(const wxString& WXUNUSED(hostname),
1230 int WXUNUSED(port))
1231{
223d09f6 1232 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
1233
1234 // nothing to do - we don't use this
1235}
1236
1237void wxDialUpManagerMSW::SetConnectCommand(const wxString& WXUNUSED(dial),
1238 const wxString& WXUNUSED(hangup))
1239{
223d09f6 1240 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
a0b4c98b
VZ
1241
1242 // nothing to do - we don't use this
1243}
1244
1245// ----------------------------------------------------------------------------
1246// callbacks
1247// ----------------------------------------------------------------------------
1248
1249static DWORD wxRasMonitorThread(wxRasThreadData *data)
1250{
1251 HANDLE handles[2];
1252 handles[0] = data->hEventRas;
1253 handles[1] = data->hEventQuit;
1254
d71cc120 1255 bool cont = true;
a0b4c98b
VZ
1256 while ( cont )
1257 {
d71cc120 1258 DWORD dwRet = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
a0b4c98b
VZ
1259
1260 switch ( dwRet )
1261 {
1262 case WAIT_OBJECT_0:
1263 // RAS connection status changed
1264 SendMessage(data->hWnd, wxWM_RAS_STATUS_CHANGED,
1265 0, (LPARAM)data);
1266 break;
1267
1268 case WAIT_OBJECT_0 + 1:
d71cc120 1269 cont = false;
a0b4c98b
VZ
1270 break;
1271
97247d36 1272 default:
9a83f860 1273 wxFAIL_MSG( wxT("unexpected return of WaitForMultipleObjects()") );
97247d36
VZ
1274 // fall through
1275
a0b4c98b 1276 case WAIT_FAILED:
97247d36
VZ
1277 // using wxLogLastError() from here is dangerous: we risk to
1278 // deadlock the main thread if wxLog sends output to GUI
1279 DWORD err = GetLastError();
141f4958
WS
1280 wxMessageOutputDebug dbg;
1281 dbg.Printf
97247d36
VZ
1282 (
1283 wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"),
1284 err,
1285 wxSysErrorMsg(err)
1286 );
97247d36
VZ
1287
1288 // no sense in continuing, who knows if the handles we're
1289 // waiting for even exist yet...
1290 return (DWORD)-1;
a0b4c98b
VZ
1291 }
1292 }
1293
97247d36
VZ
1294 // we don't need it any more now and if this thread ran, it is our
1295 // responsability to free the data
1296 delete data;
1297
a0b4c98b
VZ
1298 return 0;
1299}
1300
1301static LRESULT APIENTRY wxRasStatusWindowProc(HWND hWnd, UINT message,
1302 WPARAM wParam, LPARAM lParam)
1303{
cd6af1cb 1304 switch ( message )
a0b4c98b 1305 {
cd6af1cb
VZ
1306 case wxWM_RAS_STATUS_CHANGED:
1307 {
1308 wxRasThreadData *data = (wxRasThreadData *)lParam;
1309 data->dialUpManager->OnConnectStatusChange();
1310 }
1311 break;
2690830e 1312
cd6af1cb
VZ
1313 case wxWM_RAS_DIALING_PROGRESS:
1314 {
1315 wxDialUpManagerMSW *dialMan = wxDialUpManagerMSW::GetDialer();
1316
1317 dialMan->OnDialProgress((RASCONNSTATE)wParam, lParam);
1318 }
1319 break;
1320
1321 default:
1322 return ::DefWindowProc(hWnd, message, wParam, lParam);
2690830e 1323 }
a0b4c98b
VZ
1324
1325 return 0;
1326}
1327
2eb10e2a 1328static void WINAPI wxRasDialFunc(UINT WXUNUSED(unMsg),
a0b4c98b
VZ
1329 RASCONNSTATE rasconnstate,
1330 DWORD dwError)
1331{
1332 wxDialUpManagerMSW *dialUpManager = wxDialUpManagerMSW::GetDialer();
1333
223d09f6 1334 wxCHECK_RET( dialUpManager, wxT("who started to dial then?") );
a0b4c98b 1335
2a1f999f 1336 SendMessage(wxDialUpManagerMSW::GetRasWindow(), wxWM_RAS_DIALING_PROGRESS,
2690830e 1337 rasconnstate, dwError);
a0b4c98b
VZ
1338}
1339
1c25d245
VZ
1340#endif // __BORLANDC__
1341
a0b4c98b 1342#endif // wxUSE_DIALUP_MANAGER