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