1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 4 * 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 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 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. 16 */ 17 18#include "stdafx.h" 19 20#include <assert.h> 21#include <stdio.h> 22 23#include "dns_sd.h" 24 25// Constants 26 27#define BONJOUR_EVENT ( WM_USER + 0x100 ) // Message sent to the Window when a Bonjour event occurs. 28 29// Prototypes 30 31static LRESULT CALLBACK WndProc( HWND inWindow, UINT inMsg, WPARAM inWParam, LPARAM inLParam ); 32 33static void DNSSD_API 34 BrowserCallBack( 35 DNSServiceRef inServiceRef, 36 DNSServiceFlags inFlags, 37 uint32_t inIFI, 38 DNSServiceErrorType inError, 39 const char * inName, 40 const char * inType, 41 const char * inDomain, 42 void * inContext ); 43 44// Globals 45 46DNSServiceRef gServiceRef = NULL; 47 48// Main entry point for application. 49 50int _tmain( int argc, _TCHAR *argv[] ) 51{ 52 HINSTANCE instance; 53 WNDCLASSEX wcex; 54 HWND wind; 55 MSG msg; 56 DNSServiceErrorType err; 57 58 (void) argc; // Unused 59 (void) argv; // Unused 60 61 // Create the window. This window won't actually be shown, but it demonstrates how to use Bonjour 62 // with Windows GUI applications by having Bonjour events processed as messages to a Window. 63 64 instance = GetModuleHandle( NULL ); 65 assert( instance ); 66 67 wcex.cbSize = sizeof( wcex ); 68 wcex.style = 0; 69 wcex.lpfnWndProc = (WNDPROC) WndProc; 70 wcex.cbClsExtra = 0; 71 wcex.cbWndExtra = 0; 72 wcex.hInstance = instance; 73 wcex.hIcon = NULL; 74 wcex.hCursor = NULL; 75 wcex.hbrBackground = NULL; 76 wcex.lpszMenuName = NULL; 77 wcex.lpszClassName = TEXT( "BonjourExample" ); 78 wcex.hIconSm = NULL; 79 RegisterClassEx( &wcex ); 80 81 wind = CreateWindow( wcex.lpszClassName, wcex.lpszClassName, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 82 0, NULL, NULL, instance, NULL ); 83 assert( wind ); 84 85 // Start browsing for services and associate the Bonjour browser with our window using the 86 // WSAAsyncSelect mechanism. Whenever something related to the Bonjour browser occurs, our 87 // private Windows message will be sent to our window so we can give Bonjour a chance to 88 // process it. This allows Bonjour to avoid using a secondary thread (and all the issues 89 // with synchronization that would introduce), but still process everything asynchronously. 90 // This also simplifies app code because Bonjour will only run when we explicitly call it. 91 92 err = DNSServiceBrowse( 93 &gServiceRef, // Receives reference to Bonjour browser object. 94 0, // No flags. 95 kDNSServiceInterfaceIndexAny, // Browse on all network interfaces. 96 "_http._tcp", // Browse for HTTP service types. 97 NULL, // Browse on the default domain (e.g. local.). 98 BrowserCallBack, // Callback function when Bonjour events occur. 99 NULL ); // No callback context needed. 100 assert( err == kDNSServiceErr_NoError ); 101 102 err = WSAAsyncSelect( (SOCKET) DNSServiceRefSockFD( gServiceRef ), wind, BONJOUR_EVENT, FD_READ | FD_CLOSE ); 103 assert( err == kDNSServiceErr_NoError ); 104 105 fprintf( stderr, "Browsing for _http._tcp\n" ); 106 107 // Main event loop for the application. All Bonjour events are dispatched while in this loop. 108 109 while( GetMessage( &msg, NULL, 0, 0 ) ) 110 { 111 TranslateMessage( &msg ); 112 DispatchMessage( &msg ); 113 } 114 115 // Clean up Bonjour. This is not strictly necessary since the normal process cleanup will 116 // close Bonjour socket(s) and release memory, but it's here to demonstrate how to do it. 117 118 if( gServiceRef ) 119 { 120 WSAAsyncSelect( (SOCKET) DNSServiceRefSockFD( gServiceRef ), wind, BONJOUR_EVENT, 0 ); 121 DNSServiceRefDeallocate( gServiceRef ); 122 } 123 return( 0 ); 124} 125 126// Callback for the Window. Bonjour events are delivered here. 127 128static LRESULT CALLBACK WndProc( HWND inWindow, UINT inMsg, WPARAM inWParam, LPARAM inLParam ) 129{ 130 LRESULT result; 131 DNSServiceErrorType err; 132 133 switch( inMsg ) 134 { 135 case BONJOUR_EVENT: 136 137 // Process the Bonjour event. All Bonjour callbacks occur from within this function. 138 // If an error occurs while trying to process the result, it most likely means that 139 // something serious has gone wrong with Bonjour, such as it being terminated. This 140 // does not normally occur, but code should be prepared to handle it. If the error 141 // is ignored, the window will receive a constant stream of BONJOUR_EVENT messages so 142 // if an error occurs, we disassociate the DNSServiceRef from the window, deallocate 143 // it, and invalidate the reference so we don't try to deallocate it again on quit. 144 // Since this is a simple example app, if this error occurs, we quit the app too. 145 146 err = DNSServiceProcessResult( gServiceRef ); 147 if( err != kDNSServiceErr_NoError ) 148 { 149 fprintf( stderr, "### ERROR! serious Bonjour error: %d\n", err ); 150 151 WSAAsyncSelect( (SOCKET) DNSServiceRefSockFD( gServiceRef ), inWindow, BONJOUR_EVENT, 0 ); 152 DNSServiceRefDeallocate( gServiceRef ); 153 gServiceRef = NULL; 154 155 PostQuitMessage( 0 ); 156 } 157 result = 0; 158 break; 159 160 default: 161 result = DefWindowProc( inWindow, inMsg, inWParam, inLParam ); 162 break; 163 } 164 return( result ); 165} 166 167// Callback for Bonjour browser events. Called when services are added or removed. 168 169static void DNSSD_API 170 BrowserCallBack( 171 DNSServiceRef inServiceRef, 172 DNSServiceFlags inFlags, 173 uint32_t inIFI, 174 DNSServiceErrorType inError, 175 const char * inName, 176 const char * inType, 177 const char * inDomain, 178 void * inContext ) 179{ 180 (void) inServiceRef; // Unused 181 (void) inContext; // Unused 182 183 if( inError == kDNSServiceErr_NoError ) 184 { 185 const char * action; 186 const char * more; 187 188 if( inFlags & kDNSServiceFlagsAdd ) action = "ADD"; 189 else action = "RMV"; 190 if( inFlags & kDNSServiceFlagsMoreComing ) more = " (MORE)"; 191 else more = ""; 192 193 fprintf( stderr, "%s %30s.%s%s on interface %d%s\n", action, inName, inType, inDomain, (int) inIFI, more ); 194 } 195 else 196 { 197 fprintf( stderr, "Bonjour browser error occurred: %d\n", inError ); 198 } 199} 200