Zero Configuration Networking: The Definitive Guide

7.5. Event Handling with Microsoft Windows GetMessage( ) Message Loop

There are some differences in working with the Windows event loop. In this example, you will configure and create a window that is not displayed in the application. This gives you a template for developing GUI-based Zeroconf applications for Windows. The Zeroconf events are processed as messages to this window. Here is the outline of the HandleEvents( ) function for Windows:

void HandleEvents(DNSServiceRef inServiceRef) { //... Configure and create a window that is not shown but that // is used to process DNS-SD events as messages to the window. wind = CreateWindow(wcex.lpszClassName, wcex.lpszClassName, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, instance, NULL); // ... Associate the DNS-SD browser with our window err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(gServiceRef), wind, DNSSD_EVENT, FD_READ | FD_CLOSE); assert(err == kDNSServiceErr_NoError); // DNS-SD events are dispatched while in this loop. while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // Clean up. WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(gServiceRef), wind, DNSSD_EVENT, 0); }

When a window event is received, it is processed in the callback function WndProc( ). If the event is a DNS-SD event, it is passed on to DNSServiceProcessResult( ) as before. Here is the sketch of WndProc( ):

static LRESULT CALLBACK WndProc(HWND inWindow, UINT inMsg, WPARAM inWParam, LPARAM inLParam) { LRESULT result; switch(inMsg) { case DNSSD_EVENT: DNSServiceProcessResult(gServiceRef); result = 0; break; //... } return(result); }

All of the details are provided in the code listing in Example 7-9.

Example 7-9. Windows event loop example

#include "stdafx.h" #include <assert.h> #include <stdio.h> #include <dns_sd.h> // Constants #define DNSSD_EVENT (WM_USER + 0x100) // Message sent to Window when a DNS-SD event occurs. // Prototypes void HandleEvents(DNSServiceRef inServiceRef); static LRESULT CALLBACK WndProc(HWND inWindow, UINT inMsg, WPARAM inWParam, LPARAM inLParam); static void DNSSD_API BrowserCallBack(DNSServiceRef inServiceRef, DNSServiceFlags inFlags, uint32_t inIFI, DNSServiceErrorType inError, const char * inName, const char * inType, const char * inDomain, void * inContext); // Globals static DNSServiceRef gServiceRef = NULL; // Main entry point for application. void HandleEvents(DNSServiceRef inServiceRef) { HINSTANCE instance; WNDCLASSEX wcex; HWND wind; MSG msg; int err; gServiceRef = inServiceRef; // Create the window. This window won't actually be shown, // but it demonstrates how to use DNS-SD with Windows GUI // applications by having DNS-SD events processed as messages // to a Window. instance = GetModuleHandle(NULL); assert(instance); wcex.cbSize = sizeof(wcex); wcex.style = 0; wcex.lpfnWndProc = (WNDPROC) WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = instance; wcex.hIcon = NULL; wcex.hCursor = NULL; wcex.hbrBackground = NULL; wcex.lpszMenuName = NULL; wcex.lpszClassName = TEXT("ZeroconfExample"); wcex.hIconSm = NULL; RegisterClassEx(&wcex); wind = CreateWindow(wcex.lpszClassName, wcex.lpszClassName, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, instance, NULL); assert(wind); // Associate the DNS-SD browser with our window // using the WSAAsyncSelect mechanism. Whenever something // related to the DNS-SD browser occurs, our private Windows message // will be sent to our window so we can give DNS-SD a // chance to process it. This allows DNS-SD to avoid using a // secondary thread (and all the issues with synchronization that // would introduce), but still process everything asynchronously. // This also simplifies app code because DNS-SD will only run when we // explicitly call it. err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(gServiceRef), wind, DNSSD_EVENT, FD_READ | FD_CLOSE); assert(err == kDNSServiceErr_NoError); // Main event loop for the application. All DNS-SD events are // dispatched while in this loop. while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // Clean up. This is not strictly necessary since the normal // process cleanup will close DNS-SD socket(s) and release memory, // but it's here to demonstrate how to do it. WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(gServiceRef), wind, DNSSD_EVENT, 0); } // Callback for the Window. DNS-SD events are delivered here. static LRESULT CALLBACK WndProc(HWND inWindow, UINT inMsg, WPARAM inWParam, LPARAM inLParam) { LRESULT result; switch(inMsg) { case DNSSD_EVENT: // Process the DNS-SD event. All DNS-SD callbacks occur from // within this function. if (DNSServiceProcessResult(gServiceRef) != kDNSServiceErr_NoError) result = -1; else result = 0; break; default: result = DefWindowProc(inWindow, inMsg, inWParam, inLParam); break; } return(result); }

Категории