2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
27 $Log: BrowserDialog.cpp,v $
28 Revision 1.5 2004/01/30 02:56:33 bradley
29 Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
31 Revision 1.4 2003/10/16 09:21:56 bradley
32 Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
34 Revision 1.3 2003/10/14 03:28:50 bradley
35 Insert services in sorted order to make them easier to find. Defer service adds/removes to the main
36 thread to avoid potential problems with multi-threaded MFC message map access. Added some asserts.
38 Revision 1.2 2003/10/10 03:43:34 bradley
39 Added support for launching a web browser to go to the browsed web site on a single-tap.
41 Revision 1.1 2003/08/21 02:16:10 bradley
42 Rendezvous Browser for HTTP services for Windows CE/PocketPC.
48 #include "Application.h"
50 #include "DNSServices.h"
52 #include "BrowserDialog.h"
57 static char THIS_FILE
[] = __FILE__
;
60 //===========================================================================================================================
62 //===========================================================================================================================
64 #define WM_USER_SERVICE_ADD ( WM_USER + 0x100 )
65 #define WM_USER_SERVICE_REMOVE ( WM_USER + 0x101 )
67 //===========================================================================================================================
69 //===========================================================================================================================
71 BEGIN_MESSAGE_MAP(BrowserDialog
, CDialog
)
72 //{{AFX_MSG_MAP(BrowserDialog)
73 ON_NOTIFY(NM_CLICK
, IDC_BROWSE_LIST
, OnBrowserListDoubleClick
)
74 ON_MESSAGE( WM_USER_SERVICE_ADD
, OnServiceAdd
)
75 ON_MESSAGE( WM_USER_SERVICE_REMOVE
, OnServiceRemove
)
79 static DWORD
UTF8StringToStringObject( const char *inUTF8
, CString
&inObject
);
81 //===========================================================================================================================
83 //===========================================================================================================================
85 BrowserDialog::BrowserDialog( CWnd
*inParent
)
86 : CDialog( BrowserDialog::IDD
, inParent
)
88 //{{AFX_DATA_INIT(BrowserDialog)
89 // NOTE: the ClassWizard will add member initialization here
92 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32.
94 mIcon
= AfxGetApp()->LoadIcon( IDR_MAINFRAME
);
98 //===========================================================================================================================
100 //===========================================================================================================================
102 void BrowserDialog::DoDataExchange( CDataExchange
*pDX
)
104 CDialog::DoDataExchange(pDX
);
105 //{{AFX_DATA_MAP(BrowserDialog)
106 DDX_Control(pDX
, IDC_BROWSE_LIST
, mBrowserList
);
110 //===========================================================================================================================
112 //===========================================================================================================================
114 BOOL
BrowserDialog::OnInitDialog()
118 CDialog::OnInitDialog();
120 // Set the icon for this dialog. The framework does this automatically when the application's main window is not a dialog.
122 SetIcon( mIcon
, TRUE
); // Set big icon
123 SetIcon( mIcon
, FALSE
); // Set small icon
125 CenterWindow( GetDesktopWindow() );
131 s
.LoadString( IDS_BROWSER_LIST_COLUMN_NAME
);
132 mBrowserList
.GetWindowRect( rect
);
133 mBrowserList
.InsertColumn( 0, s
, LVCFMT_LEFT
, rect
.Width() - 8 );
135 // Start browsing for services.
139 err
= DNSBrowserCreate( 0, OnBrowserCallBack
, this, &mBrowser
);
142 AfxMessageBox( IDP_SOCKETS_INIT_FAILED
);
146 err
= DNSBrowserStartServiceSearch( mBrowser
, kDNSBrowserFlagAutoResolve
, "_http._tcp", NULL
);
149 AfxMessageBox( IDP_SOCKETS_INIT_FAILED
);
158 //===========================================================================================================================
159 // OnBrowserListDoubleClick
160 //===========================================================================================================================
162 void BrowserDialog::OnBrowserListDoubleClick( NMHDR
*pNMHDR
, LRESULT
*pResult
)
166 (void) pNMHDR
; // Unused
168 selectedItem
= mBrowserList
.GetNextItem( -1, LVNI_SELECTED
);
169 if( selectedItem
>= 0 )
171 BrowserEntry
* entry
;
175 // Build the URL from the IP and optional TXT record.
177 entry
= &mBrowserEntries
[ selectedItem
];
178 url
+= "http://" + entry
->ip
;
180 if( temp
.Find( TEXT( "path=" ) ) == 0 )
184 if( temp
.Find( '/' ) != 0 )
190 // Let the system open the URL in the correct app.
192 SHELLEXECUTEINFO info
;
194 info
.cbSize
= sizeof( info
);
199 info
.lpParameters
= NULL
;
200 info
.lpDirectory
= NULL
;
201 info
.nShow
= SW_SHOWNORMAL
;
202 info
.hInstApp
= NULL
;
204 ShellExecuteEx( &info
);
209 //===========================================================================================================================
210 // OnBrowserCallBack [static]
211 //===========================================================================================================================
214 BrowserDialog::OnBrowserCallBack(
217 DNSStatus inStatusCode
,
218 const DNSBrowserEvent
* inEvent
)
220 BrowserDialog
* dialog
;
221 BrowserEntry
* entry
;
224 DNS_UNUSED( inStatusCode
);
225 dialog
= reinterpret_cast < BrowserDialog
* > ( inContext
);
228 switch( inEvent
->type
)
230 case kDNSBrowserEventTypeResolved
:
231 if( inEvent
->data
.resolved
->address
.addressType
== kDNSNetworkAddressTypeIPv4
)
235 sprintf( ip
, "%u.%u.%u.%u:%u",
236 inEvent
->data
.resolved
->address
.u
.ipv4
.addr
.v8
[ 0 ],
237 inEvent
->data
.resolved
->address
.u
.ipv4
.addr
.v8
[ 1 ],
238 inEvent
->data
.resolved
->address
.u
.ipv4
.addr
.v8
[ 2 ],
239 inEvent
->data
.resolved
->address
.u
.ipv4
.addr
.v8
[ 3 ],
240 ( inEvent
->data
.resolved
->address
.u
.ipv4
.port
.v8
[ 0 ] << 8 ) |
241 inEvent
->data
.resolved
->address
.u
.ipv4
.port
.v8
[ 1 ] );
243 entry
= new BrowserEntry
;
247 UTF8StringToStringObject( inEvent
->data
.resolved
->name
, entry
->name
);
248 UTF8StringToStringObject( ip
, entry
->ip
);
249 UTF8StringToStringObject( inEvent
->data
.resolved
->textRecord
, entry
->text
);
251 posted
= ::PostMessage( dialog
->GetSafeHwnd(), WM_USER_SERVICE_ADD
, 0, (LPARAM
) entry
);
261 case kDNSBrowserEventTypeRemoveService
:
262 entry
= new BrowserEntry
;
266 UTF8StringToStringObject( inEvent
->data
.removeService
.name
, entry
->name
);
268 posted
= ::PostMessage( dialog
->GetSafeHwnd(), WM_USER_SERVICE_REMOVE
, 0, (LPARAM
) entry
);
282 //===========================================================================================================================
284 //===========================================================================================================================
286 LONG
BrowserDialog::OnServiceAdd( WPARAM inWParam
, LPARAM inLParam
)
288 BrowserEntry
* entry
;
294 (void) inWParam
; // Unused
296 entry
= reinterpret_cast < BrowserEntry
* > ( inLParam
);
302 hi
= mBrowserEntries
.GetSize() - 1;
305 mid
= ( lo
+ hi
) / 2;
306 result
= entry
->name
.CompareNoCase( mBrowserEntries
[ mid
].name
);
311 else if( result
< 0 )
322 mBrowserEntries
[ mid
].ip
= entry
->ip
;
323 mBrowserEntries
[ mid
].text
= entry
->text
;
331 mBrowserEntries
.InsertAt( mid
, *entry
);
332 mBrowserList
.InsertItem( mid
, entry
->name
);
338 //===========================================================================================================================
340 //===========================================================================================================================
342 LONG
BrowserDialog::OnServiceRemove( WPARAM inWParam
, LPARAM inLParam
)
344 BrowserEntry
* entry
;
350 (void) inWParam
; // Unused
352 entry
= reinterpret_cast < BrowserEntry
* > ( inLParam
);
358 hi
= mBrowserEntries
.GetSize() - 1;
361 mid
= ( lo
+ hi
) / 2;
362 result
= entry
->name
.CompareNoCase( mBrowserEntries
[ mid
].name
);
367 else if( result
< 0 )
378 mBrowserList
.DeleteItem( mid
);
379 mBrowserEntries
.RemoveAt( mid
);
389 //===========================================================================================================================
390 // UTF8StringToStringObject
391 //===========================================================================================================================
393 static DWORD
UTF8StringToStringObject( const char *inUTF8
, CString
&inObject
)
401 n
= MultiByteToWideChar( CP_UTF8
, 0, inUTF8
, -1, NULL
, 0 );
404 unicode
= (wchar_t *) malloc( (size_t)( n
* sizeof( wchar_t ) ) );
405 if( !unicode
) { err
= ERROR_INSUFFICIENT_BUFFER
; goto exit
; };
407 n
= MultiByteToWideChar( CP_UTF8
, 0, inUTF8
, -1, unicode
, n
);