]> git.saurik.com Git - apple/mdnsresponder.git/blobdiff - mDNSWindows/DLLX/DNSSDService.cpp
mDNSResponder-212.1.tar.gz
[apple/mdnsresponder.git] / mDNSWindows / DLLX / DNSSDService.cpp
diff --git a/mDNSWindows/DLLX/DNSSDService.cpp b/mDNSWindows/DLLX/DNSSDService.cpp
new file mode 100755 (executable)
index 0000000..219c610
--- /dev/null
@@ -0,0 +1,1106 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+    Change History (most recent first):
+    
+$Log: DNSSDService.cpp,v $
+Revision 1.1  2009/05/26 04:43:54  herscher
+<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
+\r
+\r
+*/\r
+\r
+#pragma warning(disable:4995)\r
+\r
+#include "stdafx.h"\r
+#include <strsafe.h>\r
+#include "DNSSDService.h"\r
+#include "DNSSDEventManager.h"\r
+#include "DNSSDRecord.h"\r
+#include "TXTRecord.h"\r
+#include "StringServices.h"\r
+#include <DebugServices.h>\r
+\r
+\r
+#define WM_SOCKET (WM_APP + 100)\r
+\r
+\r
+// CDNSSDService\r
+\r
+BOOL                                           CDNSSDService::m_registeredWindowClass  = FALSE;\r
+HWND                                           CDNSSDService::m_hiddenWindow                   = NULL;\r
+CDNSSDService::SocketMap       CDNSSDService::m_socketMap;\r
+\r
+\r
+HRESULT CDNSSDService::FinalConstruct()\r
+{\r
+       DNSServiceErrorType     err     = 0;\r
+       HRESULT                         hr      = S_OK;\r
+\r
+       m_isPrimary = TRUE;\r
+       err = DNSServiceCreateConnection( &m_primary );\r
+       require_action( !err, exit, hr = E_FAIL );\r
+\r
+       if ( !m_hiddenWindow )\r
+       {\r
+               TCHAR windowClassName[ 256 ];\r
+\r
+               StringCchPrintf( windowClassName, sizeof( windowClassName ) / sizeof( TCHAR ), TEXT( "Bonjour Hidden Window %d" ), GetProcessId( NULL ) );\r
+\r
+               if ( !m_registeredWindowClass )\r
+               {\r
+                       WNDCLASS        wc;\r
+                       ATOM            atom;\r
+\r
+                       wc.style                        = 0;\r
+                       wc.lpfnWndProc          = WndProc;\r
+                       wc.cbClsExtra           = 0;\r
+                       wc.cbWndExtra           = 0;\r
+                       wc.hInstance            = NULL;\r
+                       wc.hIcon                        = NULL;\r
+                       wc.hCursor                      = NULL;\r
+                       wc.hbrBackground        = NULL;\r
+                       wc.lpszMenuName         = NULL;\r
+                       wc.lpszClassName        = windowClassName;\r
+\r
+                       atom = RegisterClass(&wc);\r
+                       require_action( atom != NULL, exit, hr = E_FAIL );\r
+\r
+                       m_registeredWindowClass = TRUE;\r
+               }\r
+\r
+               m_hiddenWindow = CreateWindow( windowClassName, windowClassName, WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandle( NULL ), NULL );\r
+               require_action( m_hiddenWindow != NULL, exit, hr = E_FAIL );\r
+       }\r
+\r
+       err = WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, WM_SOCKET, FD_READ );\r
+       require_action( !err, exit, hr = E_FAIL );\r
+\r
+       m_socketMap[ DNSServiceRefSockFD( m_primary ) ] = this;\r
+\r
+exit:\r
+\r
+       return hr;\r
+}\r
+\r
+\r
+void CDNSSDService::FinalRelease()\r
+{\r
+       dlog( kDebugLevelTrace, "FinalRelease()\n" ); \r
+       Stop();\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
+{\r
+       CComObject<CDNSSDService>       *       object  = NULL;\r
+       DNSServiceRef                                   subord  = NULL;\r
+       DNSServiceErrorType                             err             = 0;\r
+       HRESULT                                                 hr              = 0;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *service = NULL;\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDService>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       subord = m_primary;\r
+       err = DNSServiceEnumerateDomains( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetPrimaryRef( m_primary );\r
+       object->SetSubordRef( subord );\r
+       object->SetEventManager( eventManager );\r
+\r
+       *service = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service )\r
+{\r
+       CComObject<CDNSSDService>       *       object          = NULL;\r
+       std::string                                             regtypeUTF8;\r
+       std::string                                             domainUTF8;\r
+       DNSServiceRef                                   subord          = NULL;\r
+       DNSServiceErrorType                             err                     = 0;\r
+       HRESULT                                                 hr                      = 0;\r
+       BOOL                                                    ok;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *service = NULL;\r
+\r
+       // Convert BSTR params to utf8\r
+       ok = BSTRToUTF8( regtype, regtypeUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+       ok = BSTRToUTF8( domain, domainUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDService>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       subord = m_primary;\r
+       err = DNSServiceBrowse( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, regtypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, ( DNSServiceBrowseReply ) &BrowseReply, object );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetPrimaryRef( m_primary );\r
+       object->SetSubordRef( subord );\r
+       object->SetEventManager( eventManager );\r
+\r
+       *service = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service)\r
+{\r
+       CComObject<CDNSSDService>       *       object                  = NULL;\r
+       std::string                                             serviceNameUTF8;\r
+       std::string                                             regTypeUTF8;\r
+       std::string                                             domainUTF8;\r
+       DNSServiceRef                                   subord                  = NULL;\r
+       DNSServiceErrorType                             err                             = 0;\r
+       HRESULT                                                 hr                              = 0;\r
+       BOOL                                                    ok;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *service = NULL;\r
+\r
+       // Convert BSTR params to utf8\r
+       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+       ok = BSTRToUTF8( regType, regTypeUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+       ok = BSTRToUTF8( domain, domainUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDService>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       subord = m_primary;\r
+       err = DNSServiceResolve( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetPrimaryRef( m_primary );\r
+       object->SetSubordRef( subord );\r
+       object->SetEventManager( eventManager );\r
+\r
+       *service = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
+{\r
+       CComObject<CDNSSDService>       *       object                  = NULL;\r
+       std::string                                             serviceNameUTF8;\r
+       std::string                                             regTypeUTF8;\r
+       std::string                                             domainUTF8;\r
+       std::string                                             hostUTF8;\r
+       const void                                      *       txtRecord               = NULL;\r
+       uint16_t                                                txtLen                  = 0;\r
+       DNSServiceRef                                   subord                  = NULL;\r
+       DNSServiceErrorType                             err                             = 0;\r
+       HRESULT                                                 hr                              = 0;\r
+       BOOL                                                    ok;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *service = NULL;\r
+\r
+       // Convert BSTR params to utf8\r
+       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+       ok = BSTRToUTF8( regType, regTypeUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+       ok = BSTRToUTF8( domain, domainUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+       ok = BSTRToUTF8( host, hostUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDService>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       if ( record )\r
+       {\r
+               CComObject< CTXTRecord > * realTXTRecord;\r
+\r
+               realTXTRecord = ( CComObject< CTXTRecord >* ) record;\r
+\r
+               txtRecord       = realTXTRecord->GetBytes();\r
+               txtLen          = realTXTRecord->GetLen();\r
+       }\r
+\r
+       subord = m_primary;\r
+       err = DNSServiceRegister( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, hostUTF8.c_str(), htons( port ), txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetPrimaryRef( m_primary );\r
+       object->SetSubordRef( subord );\r
+       object->SetEventManager( eventManager );\r
+\r
+       *service = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
+{\r
+       CComObject<CDNSSDService>       *       object                  = NULL;\r
+       DNSServiceRef                                   subord                  = NULL;\r
+       std::string                                             fullNameUTF8;\r
+       DNSServiceErrorType                             err                             = 0;\r
+       HRESULT                                                 hr                              = 0;\r
+       BOOL                                                    ok;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *service = NULL;\r
+\r
+       // Convert BSTR params to utf8\r
+       ok = BSTRToUTF8( fullname, fullNameUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDService>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       subord = m_primary;\r
+       err = DNSServiceQueryRecord( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetPrimaryRef( m_primary );\r
+       object->SetSubordRef( subord );\r
+       object->SetEventManager( eventManager );\r
+\r
+       *service = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::RegisterRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record)\r
+{\r
+       CComObject<CDNSSDRecord>        *       object                  = NULL;\r
+       DNSRecordRef                                    rref                    = NULL;\r
+       std::string                                             fullNameUTF8;\r
+       std::vector< BYTE >                             byteArray;\r
+       const void                                      *       byteArrayPtr    = NULL;\r
+       DNSServiceErrorType                             err                             = 0;\r
+       HRESULT                                                 hr                              = 0;\r
+       BOOL                                                    ok;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *object = NULL;\r
+\r
+       // Convert BSTR params to utf8\r
+       ok = BSTRToUTF8( fullName, fullNameUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+\r
+       // Convert the VARIANT\r
+       ok = VariantToByteArray( &rdata, byteArray );\r
+       require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDRecord>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       err = DNSServiceRegisterRecord( m_primary, &rref, flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl, &RegisterRecordReply, object );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetServiceObject( this );\r
+       object->SetRecordRef( rref );\r
+       this->SetEventManager( eventManager );\r
+\r
+       *record = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::AddRecord(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record)\r
+{\r
+       CComObject<CDNSSDRecord>        *       object                  = NULL;\r
+       DNSRecordRef                                    rref                    = NULL;\r
+       std::vector< BYTE >                             byteArray;\r
+       const void                                      *       byteArrayPtr    = NULL;\r
+       DNSServiceErrorType                             err                             = 0;\r
+       HRESULT                                                 hr                              = 0;\r
+       BOOL                                                    ok;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *object = NULL;\r
+\r
+       // Convert the VARIANT\r
+       ok = VariantToByteArray( &rdata, byteArray );\r
+       require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDRecord>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       err = DNSServiceAddRecord( m_primary, &rref, flags, rrtype, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetServiceObject( this );\r
+       object->SetRecordRef( rref );\r
+\r
+       *record = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+STDMETHODIMP CDNSSDService::ReconfirmRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata)\r
+{\r
+       std::string                                             fullNameUTF8;\r
+       std::vector< BYTE >                             byteArray;\r
+       const void                                      *       byteArrayPtr    = NULL;\r
+       DNSServiceErrorType                             err                             = 0;\r
+       HRESULT                                                 hr                              = 0;\r
+       BOOL                                                    ok;\r
+\r
+       // Convert BSTR params to utf8\r
+       ok = BSTRToUTF8( fullName, fullNameUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+\r
+       // Convert the VARIANT\r
+       ok = VariantToByteArray( &rdata, byteArray );\r
+       require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       err = DNSServiceReconfirmRecord( flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL );\r
+       require_noerr( err, exit );\r
+\r
+exit:\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::GetProperty(BSTR prop, VARIANT * value )\r
+{\r
+       std::string                     propUTF8;\r
+       std::vector< BYTE >     byteArray;\r
+       SAFEARRAY               *       psa                     = NULL;\r
+       BYTE                    *       pData           = NULL;\r
+       uint32_t                        elems           = 0;\r
+       DNSServiceErrorType     err                     = 0;\r
+       BOOL                            ok = TRUE;\r
+\r
+       // Convert BSTR params to utf8\r
+       ok = BSTRToUTF8( prop, propUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+\r
+       // Setup the byte array\r
+       require_action( V_VT( value ) == ( VT_ARRAY|VT_UI1 ), exit, err = kDNSServiceErr_Unknown );\r
+       psa = V_ARRAY( value );\r
+       require_action( psa, exit, err = kDNSServiceErr_Unknown );\r
+       require_action( SafeArrayGetDim( psa ) == 1, exit, err = kDNSServiceErr_Unknown );\r
+       byteArray.reserve( psa->rgsabound[0].cElements );\r
+       byteArray.assign( byteArray.capacity(), 0 );\r
+       elems = ( uint32_t ) byteArray.capacity();\r
+\r
+       // Call the function and package the return value in the Variant\r
+       err = DNSServiceGetProperty( propUTF8.c_str(), &byteArray[ 0 ], &elems );\r
+       require_noerr( err, exit );\r
+       ok = ByteArrayToVariant( &byteArray[ 0 ], elems, value );\r
+       require_action( ok, exit, err = kDNSSDError_Unknown );\r
+\r
+exit:\r
+\r
+       if ( psa )\r
+       {\r
+               SafeArrayUnaccessData( psa );\r
+               psa = NULL;\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+STDMETHODIMP CDNSSDService::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
+{\r
+       CComObject<CDNSSDService>       *       object                  = NULL;\r
+       DNSServiceRef                                   subord                  = NULL;\r
+       std::string                                             hostNameUTF8;\r
+       DNSServiceErrorType                             err                             = 0;\r
+       HRESULT                                                 hr                              = 0;\r
+       BOOL                                                    ok;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *service = NULL;\r
+\r
+       // Convert BSTR params to utf8\r
+       ok = BSTRToUTF8( hostName, hostNameUTF8 );\r
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDService>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       subord = m_primary;\r
+       err = DNSServiceGetAddrInfo( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetPrimaryRef( m_primary );\r
+       object->SetSubordRef( subord );\r
+       object->SetEventManager( eventManager );\r
+\r
+       *service = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
+{\r
+       CComObject<CDNSSDService>       *       object                  = NULL;\r
+       DNSServiceRef                                   subord                  = NULL;\r
+       DNSServiceProtocol                              prot                    = 0;\r
+       DNSServiceErrorType                             err                             = 0;\r
+       HRESULT                                                 hr                              = 0;\r
+\r
+       check( m_primary );\r
+\r
+       // Initialize\r
+       *service = NULL;\r
+\r
+       try\r
+       {\r
+               object = new CComObject<CDNSSDService>();\r
+       }\r
+       catch ( ... )\r
+       {\r
+               object = NULL;\r
+       }\r
+\r
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
+       object->AddRef();\r
+\r
+       prot = ( addressFamily | protocol );\r
+\r
+       subord = m_primary;\r
+       err = DNSServiceNATPortMappingCreate( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, prot, htons( internalPort ), htons( externalPort ), ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object );\r
+       require_noerr( err, exit );\r
+\r
+       object->SetPrimaryRef( m_primary );\r
+       object->SetSubordRef( subord );\r
+       object->SetEventManager( eventManager );\r
+\r
+       *service = object;\r
+\r
+exit:\r
+\r
+       if ( err && object )\r
+       {\r
+               object->Release();\r
+       }\r
+\r
+       return err;\r
+}\r
+\r
+\r
+STDMETHODIMP CDNSSDService::Stop(void)\r
+{\r
+       if ( !m_stopped )\r
+       {\r
+               m_stopped = TRUE;\r
+\r
+               dlog( kDebugLevelTrace, "Stop()\n" );\r
+\r
+               if ( m_isPrimary && m_primary )\r
+               {\r
+                       SocketMap::iterator it;\r
+\r
+                       if ( m_hiddenWindow )\r
+                       {\r
+                               WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, 0, 0 );\r
+                       }\r
+\r
+                       it = m_socketMap.find( DNSServiceRefSockFD( m_primary ) );\r
+\r
+                       if ( it != m_socketMap.end() )\r
+                       {\r
+                               m_socketMap.erase( it );\r
+                       }\r
+\r
+                       DNSServiceRefDeallocate( m_primary );\r
+                       m_primary = NULL;\r
+               }\r
+               else if ( m_subord )\r
+               {\r
+                       DNSServiceRefDeallocate( m_subord );\r
+                       m_subord = NULL;\r
+               }\r
+\r
+               if ( m_eventManager != NULL )\r
+               {\r
+                       m_eventManager->Release();\r
+                       m_eventManager = NULL;\r
+               }\r
+       }\r
+\r
+       return S_OK;\r
+}\r
+\r
+\r
+void DNSSD_API
+CDNSSDService::DomainEnumReply
+    (
+    DNSServiceRef                       sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            ifIndex,
+    DNSServiceErrorType                 errorCode,
+    const char                          *replyDomainUTF8,
+    void                                *context
+    )\r
+{\r
+       CComObject<CDNSSDService>       * service               = NULL;\r
+       CDNSSDEventManager                      * eventManager  = NULL;\r
+       int err = 0;\r
+       \r
+       service = ( CComObject< CDNSSDService>* ) context;\r
+       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
+       {\r
+               CComBSTR replyDomain;\r
+               BOOL ok;\r
+               \r
+               ok = UTF8ToBSTR( replyDomainUTF8, replyDomain );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+               if ( flags & kDNSServiceFlagsAdd )\r
+               {\r
+                       eventManager->Fire_DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );\r
+               }\r
+               else\r
+               {\r
+                       eventManager->Fire_DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );\r
+               }\r
+       }\r
+\r
+exit:\r
+\r
+       return;\r
+}\r
+\r
+\r
+void DNSSD_API
+CDNSSDService::BrowseReply
+               (
+               DNSServiceRef                       sdRef,
+               DNSServiceFlags                     flags,
+               uint32_t                            ifIndex,
+               DNSServiceErrorType                 errorCode,
+               const char                          *serviceNameUTF8,
+               const char                          *regTypeUTF8,
+               const char                          *replyDomainUTF8,
+               void                                *context
+               )\r
+{\r
+       CComObject<CDNSSDService>       * service               = NULL;\r
+       CDNSSDEventManager                      * eventManager  = NULL;\r
+       int err = 0;\r
+       \r
+       service = ( CComObject< CDNSSDService>* ) context;\r
+       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
+       {\r
+               CComBSTR        serviceName;\r
+               CComBSTR        regType;\r
+               CComBSTR        replyDomain;\r
+       \r
+               UTF8ToBSTR( serviceNameUTF8, serviceName );\r
+               UTF8ToBSTR( regTypeUTF8, regType );\r
+               UTF8ToBSTR( replyDomainUTF8, replyDomain );\r
+\r
+               if ( flags & kDNSServiceFlagsAdd )\r
+               {\r
+                       eventManager->Fire_ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );\r
+               }\r
+               else\r
+               {\r
+                       eventManager->Fire_ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );\r
+               }\r
+       }\r
+\r
+exit:\r
+\r
+       return;\r
+}\r
+\r
+\r
+void DNSSD_API\r
+CDNSSDService::ResolveReply\r
+               (
+               DNSServiceRef                       sdRef,
+               DNSServiceFlags                     flags,
+               uint32_t                            ifIndex,
+               DNSServiceErrorType                 errorCode,
+               const char                          *fullNameUTF8,
+               const char                          *hostNameUTF8,
+               uint16_t                            port,
+               uint16_t                            txtLen,
+               const unsigned char                 *txtRecord,
+               void                                *context\r
+               )\r
+{\r
+       CComObject<CDNSSDService>       * service               = NULL;\r
+       CDNSSDEventManager                      * eventManager  = NULL;\r
+       int err = 0;\r
+       \r
+       service = ( CComObject< CDNSSDService>* ) context;\r
+       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
+       {\r
+               CComBSTR                                        fullName;\r
+               CComBSTR                                        hostName;\r
+               CComBSTR                                        regType;\r
+               CComBSTR                                        replyDomain;\r
+               CComObject< CTXTRecord >*       record;\r
+               BOOL                                            ok;\r
+\r
+               ok = UTF8ToBSTR( fullNameUTF8, fullName );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+               ok = UTF8ToBSTR( hostNameUTF8, hostName );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+               try\r
+               {\r
+                       record = new CComObject<CTXTRecord>();\r
+               }\r
+               catch ( ... )\r
+               {\r
+                       record = NULL;\r
+               }\r
+\r
+               require_action( record, exit, err = kDNSServiceErr_NoMemory );\r
+               record->AddRef();\r
+\r
+               if ( txtLen > 0 )\r
+               {\r
+                       record->SetBytes( txtRecord, txtLen );\r
+               }\r
+\r
+               eventManager->Fire_ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, ntohs( port ), record );\r
+       }\r
+\r
+exit:\r
+\r
+       return;\r
+}\r
+\r
+\r
+void DNSSD_API
+CDNSSDService::RegisterReply
+               (
+               DNSServiceRef                       sdRef,
+               DNSServiceFlags                     flags,
+               DNSServiceErrorType                 errorCode,
+               const char                          *serviceNameUTF8,
+               const char                          *regTypeUTF8,
+               const char                          *domainUTF8,
+               void                                *context
+               )\r
+{\r
+       CComObject<CDNSSDService>       * service               = NULL;\r
+       CDNSSDEventManager                      * eventManager  = NULL;\r
+       int err = 0;\r
+       \r
+       service = ( CComObject< CDNSSDService>* ) context;\r
+       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
+       {\r
+               CComBSTR                                        serviceName;\r
+               CComBSTR                                        regType;\r
+               CComBSTR                                        domain;\r
+               BOOL                                            ok;\r
+\r
+               ok = UTF8ToBSTR( serviceNameUTF8, serviceName );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+               ok = UTF8ToBSTR( regTypeUTF8, regType );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+               ok = UTF8ToBSTR( domainUTF8, domain );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+               eventManager->Fire_ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain );\r
+       }\r
+\r
+exit:\r
+\r
+       return;\r
+}\r
+\r
+\r
+void DNSSD_API
+CDNSSDService::QueryRecordReply
+               (
+               DNSServiceRef                       sdRef,
+               DNSServiceFlags                     flags,
+               uint32_t                            ifIndex,
+               DNSServiceErrorType                 errorCode,
+               const char                          *fullNameUTF8,
+               uint16_t                            rrtype,
+               uint16_t                            rrclass,
+               uint16_t                            rdlen,
+               const void                          *rdata,
+               uint32_t                            ttl,
+               void                                *context
+               )\r
+{\r
+       CComObject<CDNSSDService>       * service               = NULL;\r
+       CDNSSDEventManager                      * eventManager  = NULL;\r
+       int err = 0;\r
+       \r
+       service = ( CComObject< CDNSSDService>* ) context;\r
+       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
+       {\r
+               CComBSTR        fullName;\r
+               VARIANT         var;\r
+               BOOL            ok;\r
+\r
+               ok = UTF8ToBSTR( fullNameUTF8, fullName );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+               ok = ByteArrayToVariant( rdata, rdlen, &var );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+               eventManager->Fire_QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl );\r
+       }\r
+\r
+exit:\r
+\r
+       return;\r
+}\r
+\r
+\r
+void DNSSD_API
+CDNSSDService::GetAddrInfoReply
+               (
+               DNSServiceRef                    sdRef,
+               DNSServiceFlags                  flags,
+               uint32_t                         ifIndex,
+               DNSServiceErrorType              errorCode,
+               const char                       *hostNameUTF8,
+               const struct sockaddr            *rawAddress,
+               uint32_t                         ttl,
+               void                             *context
+               )\r
+{\r
+       CComObject<CDNSSDService>       * service               = NULL;\r
+       CDNSSDEventManager                      * eventManager  = NULL;\r
+       int err = 0;\r
+       \r
+       service = ( CComObject< CDNSSDService>* ) context;\r
+       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
+       {\r
+               CComBSTR                        hostName;\r
+               DWORD                           sockaddrLen;\r
+               DNSSDAddressFamily      addressFamily;\r
+               char                            addressUTF8[INET6_ADDRSTRLEN];\r
+               DWORD                           addressLen = sizeof( addressUTF8 );\r
+               CComBSTR                        address;\r
+               BOOL                            ok;\r
+\r
+               ok = UTF8ToBSTR( hostNameUTF8, hostName );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+               switch ( rawAddress->sa_family )\r
+               {\r
+                       case AF_INET:\r
+                       {\r
+                               addressFamily   = kDNSSDAddressFamily_IPv4;\r
+                               sockaddrLen             = sizeof( sockaddr_in );\r
+                       }\r
+                       break;\r
+\r
+                       case AF_INET6:\r
+                       {\r
+                               addressFamily   = kDNSSDAddressFamily_IPv6;\r
+                               sockaddrLen             = sizeof( sockaddr_in6 );\r
+                       }\r
+                       break;\r
+               }\r
+\r
+               err = WSAAddressToStringA( ( LPSOCKADDR ) rawAddress, sockaddrLen, NULL, addressUTF8, &addressLen );\r
+               require_noerr( err, exit );\r
+               ok = UTF8ToBSTR( addressUTF8, address );\r
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
+\r
+               eventManager->Fire_AddressFound( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl );\r
+       }\r
+\r
+exit:\r
+\r
+       return;\r
+}\r
+\r
+\r
+void DNSSD_API
+CDNSSDService::NATPortMappingReply
+    (
+    DNSServiceRef                    sdRef,
+    DNSServiceFlags                  flags,
+    uint32_t                         ifIndex,
+    DNSServiceErrorType              errorCode,
+    uint32_t                         externalAddress,   /* four byte IPv4 address in network byte order */
+    DNSServiceProtocol               protocol,
+    uint16_t                         internalPort,
+    uint16_t                         externalPort,      /* may be different than the requested port     */
+    uint32_t                         ttl,               /* may be different than the requested ttl      */
+    void                             *context
+    )\r
+{\r
+       CComObject<CDNSSDService>       * service               = NULL;\r
+       CDNSSDEventManager                      * eventManager  = NULL;\r
+       int err = 0;\r
+       \r
+       service = ( CComObject< CDNSSDService>* ) context;\r
+       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
+       {\r
+               eventManager->Fire_MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), ntohs( internalPort ), ntohs( externalPort ), ttl  );\r
+       }\r
+\r
+exit:\r
+\r
+       return;\r
+}\r
+\r
+\r
+void DNSSD_API
+CDNSSDService::RegisterRecordReply
+               (
+               DNSServiceRef           sdRef,
+               DNSRecordRef            RecordRef,
+               DNSServiceFlags         flags,
+               DNSServiceErrorType     errorCode,
+               void                            *context
+               )\r
+{\r
+       CComObject<CDNSSDRecord>        * record                = NULL;\r
+       CDNSSDService                           * service               = NULL;\r
+       CDNSSDEventManager                      * eventManager  = NULL;\r
+       int err = 0;\r
+       \r
+       record = ( CComObject< CDNSSDRecord >* ) context;\r
+       require_action( record, exit, err = kDNSServiceErr_Unknown );\r
+       service = record->GetServiceObject();\r
+       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
+\r
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
+       {\r
+               eventManager->Fire_RecordRegistered( record, ( DNSSDFlags ) flags );\r
+       }\r
+\r
+exit:\r
+\r
+       return;\r
+}\r
+\r
+\r
+BOOL\r
+CDNSSDService::ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager )\r
+{\r
+       BOOL ok = FALSE;\r
+\r
+       if ( !this->Stopped() )\r
+       {\r
+               eventManager = this->GetEventManager();\r
+               require_action( eventManager, exit, ok = FALSE );\r
+\r
+               if ( !errorCode )\r
+               {\r
+                       ok = TRUE;\r
+               }\r
+               else\r
+               {\r
+                       eventManager->Fire_OperationFailed( this, ( DNSSDError ) errorCode );\r
+               }\r
+       }\r
+\r
+exit:\r
+\r
+       return ok;\r
+}\r
+\r
+\r
+LRESULT CALLBACK\r
+CDNSSDService::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )\r
+{\r
+       if ( msg == WM_SOCKET )\r
+       {\r
+               SocketMap::iterator it;\r
+                       \r
+               it = m_socketMap.find( ( SOCKET ) wParam );\r
+               check( it != m_socketMap.end() );\r
+\r
+               if ( it != m_socketMap.end() )\r
+               {\r
+                       DNSServiceProcessResult( it->second->m_primary );\r
+               }\r
+       }\r
+\r
+       return DefWindowProc(hWnd, msg, wParam, lParam);;\r
+}\r