1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
19 $Log: BonjourExample.cpp,v $
20 Revision 1.2 2006/08/14 23:23:57 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.1 2005/05/20 22:01:01 bradley
24 Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
37 #define BONJOUR_EVENT ( WM_USER + 0x100 ) // Message sent to the Window when a Bonjour event occurs.
41 static LRESULT CALLBACK
WndProc( HWND inWindow
, UINT inMsg
, WPARAM inWParam
, LPARAM inLParam
);
45 DNSServiceRef inServiceRef
,
46 DNSServiceFlags inFlags
,
48 DNSServiceErrorType inError
,
51 const char * inDomain
,
56 DNSServiceRef gServiceRef
= NULL
;
58 // Main entry point for application.
60 int _tmain( int argc
, _TCHAR
*argv
[] )
66 DNSServiceErrorType err
;
68 (void) argc
; // Unused
69 (void) argv
; // Unused
71 // Create the window. This window won't actually be shown, but it demonstrates how to use Bonjour
72 // with Windows GUI applications by having Bonjour events processed as messages to a Window.
74 instance
= GetModuleHandle( NULL
);
77 wcex
.cbSize
= sizeof( wcex
);
79 wcex
.lpfnWndProc
= (WNDPROC
) WndProc
;
82 wcex
.hInstance
= instance
;
85 wcex
.hbrBackground
= NULL
;
86 wcex
.lpszMenuName
= NULL
;
87 wcex
.lpszClassName
= TEXT( "BonjourExample" );
89 RegisterClassEx( &wcex
);
91 wind
= CreateWindow( wcex
.lpszClassName
, wcex
.lpszClassName
, 0, CW_USEDEFAULT
, 0, CW_USEDEFAULT
,
92 0, NULL
, NULL
, instance
, NULL
);
95 // Start browsing for services and associate the Bonjour browser with our window using the
96 // WSAAsyncSelect mechanism. Whenever something related to the Bonjour browser occurs, our
97 // private Windows message will be sent to our window so we can give Bonjour a chance to
98 // process it. This allows Bonjour to avoid using a secondary thread (and all the issues
99 // with synchronization that would introduce), but still process everything asynchronously.
100 // This also simplifies app code because Bonjour will only run when we explicitly call it.
102 err
= DNSServiceBrowse(
103 &gServiceRef
, // Receives reference to Bonjour browser object.
105 kDNSServiceInterfaceIndexAny
, // Browse on all network interfaces.
106 "_http._tcp", // Browse for HTTP service types.
107 NULL
, // Browse on the default domain (e.g. local.).
108 BrowserCallBack
, // Callback function when Bonjour events occur.
109 NULL
); // No callback context needed.
110 assert( err
== kDNSServiceErr_NoError
);
112 err
= WSAAsyncSelect( (SOCKET
) DNSServiceRefSockFD( gServiceRef
), wind
, BONJOUR_EVENT
, FD_READ
| FD_CLOSE
);
113 assert( err
== kDNSServiceErr_NoError
);
115 fprintf( stderr
, "Browsing for _http._tcp\n" );
117 // Main event loop for the application. All Bonjour events are dispatched while in this loop.
119 while( GetMessage( &msg
, NULL
, 0, 0 ) )
121 TranslateMessage( &msg
);
122 DispatchMessage( &msg
);
125 // Clean up Bonjour. This is not strictly necessary since the normal process cleanup will
126 // close Bonjour socket(s) and release memory, but it's here to demonstrate how to do it.
130 WSAAsyncSelect( (SOCKET
) DNSServiceRefSockFD( gServiceRef
), wind
, BONJOUR_EVENT
, 0 );
131 DNSServiceRefDeallocate( gServiceRef
);
136 // Callback for the Window. Bonjour events are delivered here.
138 static LRESULT CALLBACK
WndProc( HWND inWindow
, UINT inMsg
, WPARAM inWParam
, LPARAM inLParam
)
141 DNSServiceErrorType err
;
147 // Process the Bonjour event. All Bonjour callbacks occur from within this function.
148 // If an error occurs while trying to process the result, it most likely means that
149 // something serious has gone wrong with Bonjour, such as it being terminated. This
150 // does not normally occur, but code should be prepared to handle it. If the error
151 // is ignored, the window will receive a constant stream of BONJOUR_EVENT messages so
152 // if an error occurs, we disassociate the DNSServiceRef from the window, deallocate
153 // it, and invalidate the reference so we don't try to deallocate it again on quit.
154 // Since this is a simple example app, if this error occurs, we quit the app too.
156 err
= DNSServiceProcessResult( gServiceRef
);
157 if( err
!= kDNSServiceErr_NoError
)
159 fprintf( stderr
, "### ERROR! serious Bonjour error: %d\n", err
);
161 WSAAsyncSelect( (SOCKET
) DNSServiceRefSockFD( gServiceRef
), inWindow
, BONJOUR_EVENT
, 0 );
162 DNSServiceRefDeallocate( gServiceRef
);
165 PostQuitMessage( 0 );
171 result
= DefWindowProc( inWindow
, inMsg
, inWParam
, inLParam
);
177 // Callback for Bonjour browser events. Called when services are added or removed.
179 static void DNSSD_API
181 DNSServiceRef inServiceRef
,
182 DNSServiceFlags inFlags
,
184 DNSServiceErrorType inError
,
187 const char * inDomain
,
190 (void) inServiceRef
; // Unused
191 (void) inContext
; // Unused
193 if( inError
== kDNSServiceErr_NoError
)
198 if( inFlags
& kDNSServiceFlagsAdd
) action
= "ADD";
200 if( inFlags
& kDNSServiceFlagsMoreComing
) more
= " (MORE)";
203 fprintf( stderr
, "%s %30s.%s%s on interface %d%s\n", action
, inName
, inType
, inDomain
, (int) inIFI
, more
);
207 fprintf( stderr
, "Bonjour browser error occurred: %d\n", inError
);