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