[DNSRSLVR] Add the DNS Resolver Cache Service
authorEric Kohl <eric.kohl@reactos.org>
Sun, 27 Oct 2019 12:45:52 +0000 (13:45 +0100)
committerEric Kohl <eric.kohl@reactos.org>
Sun, 27 Oct 2019 12:48:04 +0000 (13:48 +0100)
Patch written by Peter Hater and Christoph von Wittich.

Slightly modified by me in order to
- fix bit-rot
- fix header include issues
- disable integration with dnsapi because of confusing use of DnsQweryEx().

Integration with dnsapi will follow in a future commit.

CORE-12159

base/services/CMakeLists.txt
base/services/dnsrslvr/CMakeLists.txt [new file with mode: 0644]
base/services/dnsrslvr/cache.c [new file with mode: 0644]
base/services/dnsrslvr/dnsrslvr.c [new file with mode: 0644]
base/services/dnsrslvr/dnsrslvr.rc [new file with mode: 0644]
base/services/dnsrslvr/dnsrslvr.spec [new file with mode: 0644]
base/services/dnsrslvr/precomp.h [new file with mode: 0644]
base/services/dnsrslvr/rpcserver.c [new file with mode: 0644]
media/inf/nettcpip.inf
sdk/include/reactos/idl/dnsrslvr.idl
sdk/include/reactos/windns_undoc.h

index 62b5a90..2605101 100644 (file)
@@ -2,6 +2,7 @@
 add_subdirectory(audiosrv)
 add_subdirectory(dcomlaunch)
 add_subdirectory(dhcpcsvc)
+add_subdirectory(dnsrslvr)
 add_subdirectory(eventlog)
 add_subdirectory(netlogon)
 add_subdirectory(nfsd)
diff --git a/base/services/dnsrslvr/CMakeLists.txt b/base/services/dnsrslvr/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a2821d9
--- /dev/null
@@ -0,0 +1,23 @@
+
+include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl)
+add_rpc_files(server ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/dnsrslvr.idl)
+
+list(APPEND SOURCE
+    cache.c
+    dnsrslvr.c
+    rpcserver.c
+    precomp.h
+    ${CMAKE_CURRENT_BINARY_DIR}/dnsrslvr_s.c)
+
+spec2def(dnsrslvr.dll dnsrslvr.spec ADD_IMPORTLIB)
+
+add_library(dnsrslvr SHARED ${SOURCE} dnsrslvr.rc ${CMAKE_CURRENT_BINARY_DIR}/dnsrslvr.def)
+
+if(NOT MSVC)
+    target_link_libraries(dnsrslvr ${PSEH_LIB})
+endif()
+
+set_module_type(dnsrslvr win32dll UNICODE)
+add_importlibs(dnsrslvr advapi32 rpcrt4 dnsapi iphlpapi msvcrt kernel32 ntdll)
+add_pch(dnsrslvr precomp.h SOURCE)
+add_cd_file(TARGET dnsrslvr DESTINATION reactos/system32 FOR all)
diff --git a/base/services/dnsrslvr/cache.c b/base/services/dnsrslvr/cache.c
new file mode 100644 (file)
index 0000000..6a6eee4
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS system libraries
+ * FILE:        base/services/dnsrslvr/cache.c
+ * PURPOSE:     DNS cache functions
+ * PROGRAMMER:  Peter Hater
+ */
+
+#include "precomp.h"
+
+//#define NDEBUG
+#include <debug.h>
+
+static RESOLVER_CACHE DnsCache;
+static BOOL DnsCacheInitialized = FALSE;
+
+#define DnsCacheLock()          do { EnterCriticalSection(&DnsCache.Lock); } while (0)
+#define DnsCacheUnlock()        do { LeaveCriticalSection(&DnsCache.Lock); } while (0)
+
+VOID
+DnsIntCacheInitialize(VOID)
+{
+    DPRINT("DnsIntCacheInitialize\n");
+
+    /* Check if we're initialized */
+    if (DnsCacheInitialized)
+        return;
+
+    /* Initialize the cache lock and namespace list */
+    InitializeCriticalSection((LPCRITICAL_SECTION)&DnsCache.Lock);
+    InitializeListHead(&DnsCache.RecordList);
+    DnsCacheInitialized = TRUE;
+}
+
+VOID
+DnsIntCacheFree(VOID)
+{
+    DPRINT("DnsIntCacheFree\n");
+
+    /* Check if we're initialized */
+    if (!DnsCacheInitialized)
+        return;
+
+    if (!DnsCache.RecordList.Flink)
+        return;
+
+    DnsIntCacheFlush();
+
+    DeleteCriticalSection(&DnsCache.Lock);
+    DnsCacheInitialized = FALSE;
+}
+VOID
+DnsIntCacheRemoveEntryItem(PRESOLVER_CACHE_ENTRY CacheEntry)
+{
+    DPRINT("DnsIntCacheRemoveEntryItem %p\n", CacheEntry);
+
+    /* Remove the entry from the list */
+    RemoveEntryList(&CacheEntry->CacheLink);
+    /* Free record */
+    DnsRecordListFree(CacheEntry->Record, DnsFreeRecordList);
+
+    /* Delete us */
+    HeapFree(GetProcessHeap(), 0, CacheEntry);
+}
+
+VOID
+DnsIntCacheFlush(VOID)
+{
+    PLIST_ENTRY Entry;
+    PRESOLVER_CACHE_ENTRY CacheEntry;
+
+    DPRINT("DnsIntCacheFlush\n");
+
+    /* Lock the cache */
+    DnsCacheLock();
+
+    /* Loop every entry */
+    Entry = DnsCache.RecordList.Flink;
+    while (Entry != &DnsCache.RecordList)
+    {
+        /* Get this entry */
+        CacheEntry = CONTAINING_RECORD(Entry, RESOLVER_CACHE_ENTRY, CacheLink);
+
+        /* Remove it from list */
+        DnsIntCacheRemoveEntryItem(CacheEntry);
+
+        /* Move to the next entry */
+        Entry = DnsCache.RecordList.Flink;
+    }
+
+    /* Unlock the cache */
+    DnsCacheUnlock();
+}
+
+BOOL
+DnsIntCacheGetEntryFromName(LPCWSTR Name,
+                            PDNS_RECORDW *Record)
+{
+    BOOL Ret = FALSE;
+    PRESOLVER_CACHE_ENTRY CacheEntry;
+    PLIST_ENTRY NextEntry;
+
+    DPRINT("DnsIntCacheGetEntryFromName %ws %p\n", Name, Record);
+
+    /* Assume failure */
+    *Record = NULL;
+
+    /* Lock the cache */
+    DnsCacheLock();
+
+    /* Match the Id with all the entries in the List */
+    NextEntry = DnsCache.RecordList.Flink;
+    while (NextEntry != &DnsCache.RecordList)
+    {
+        /* Get the Current Entry */
+        CacheEntry = CONTAINING_RECORD(NextEntry, RESOLVER_CACHE_ENTRY, CacheLink);
+
+        /* Check if this is the Catalog Entry ID we want */
+        if (_wcsicmp(CacheEntry->Record->pName, Name) == 0)
+        {
+            /* Copy the entry and return it */
+            *Record = DnsRecordSetCopyEx(CacheEntry->Record, DnsCharSetUnicode, DnsCharSetUnicode);
+            Ret = TRUE;
+            break;
+        }
+
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Release the cache */
+    DnsCacheUnlock();
+
+    /* Return */
+    return Ret;
+}
+
+BOOL
+DnsIntCacheRemoveEntryByName(LPCWSTR Name)
+{
+    BOOL Ret = FALSE;
+    PRESOLVER_CACHE_ENTRY CacheEntry;
+    PLIST_ENTRY NextEntry;
+
+    DPRINT("DnsIntCacheRemoveEntryByName %ws\n", Name);
+
+    /* Lock the cache */
+    DnsCacheLock();
+
+    /* Match the Id with all the entries in the List */
+    NextEntry = DnsCache.RecordList.Flink;
+    while (NextEntry != &DnsCache.RecordList)
+    {
+        /* Get the Current Entry */
+        CacheEntry = CONTAINING_RECORD(NextEntry, RESOLVER_CACHE_ENTRY, CacheLink);
+
+        /* Check if this is the Catalog Entry ID we want */
+        if (_wcsicmp(CacheEntry->Record->pName, Name) == 0)
+        {
+            /* Remove the entry */
+            DnsIntCacheRemoveEntryItem(CacheEntry);
+            Ret = TRUE;
+            break;
+        }
+
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Release the cache */
+    DnsCacheUnlock();
+
+    /* Return */
+    return Ret;
+}
+
+VOID
+DnsIntCacheAddEntry(PDNS_RECORDW Record)
+{
+    PRESOLVER_CACHE_ENTRY Entry;
+
+    DPRINT("DnsIntCacheRemoveEntryByName %p\n", Record);
+
+    /* Lock the cache */
+    DnsCacheLock();
+
+    /* Match the Id with all the entries in the List */
+    Entry = (PRESOLVER_CACHE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(*Entry));
+    if (!Entry)
+        return;
+
+    Entry->Record = DnsRecordSetCopyEx(Record, DnsCharSetUnicode, DnsCharSetUnicode);
+
+    /* Insert it to our List */
+    InsertTailList(&DnsCache.RecordList, &Entry->CacheLink);
+
+    /* Release the cache */
+    DnsCacheUnlock();
+}
diff --git a/base/services/dnsrslvr/dnsrslvr.c b/base/services/dnsrslvr/dnsrslvr.c
new file mode 100644 (file)
index 0000000..c038405
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS DNS Resolver
+ * FILE:        base/services/dnsrslvr/dnsrslvr.c
+ * PURPOSE:     DNS Resolver Service
+ * PROGRAMMER:  Christoph von Wittich
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "precomp.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ******************************************************************/
+
+HINSTANCE hDllInstance;
+SERVICE_STATUS_HANDLE ServiceStatusHandle;
+SERVICE_STATUS SvcStatus;
+static WCHAR ServiceName[] = L"Dnscache";
+
+DWORD WINAPI RpcThreadRoutine(LPVOID lpParameter);
+
+/* FUNCTIONS *****************************************************************/
+
+static
+VOID
+UpdateServiceStatus(
+    HANDLE hServiceStatus,
+    DWORD NewStatus,
+    DWORD Increment)
+{
+    if (Increment > 0)
+        SvcStatus.dwCheckPoint += Increment;
+    else
+        SvcStatus.dwCheckPoint = 0;
+
+    SvcStatus.dwCurrentState = NewStatus;
+    SetServiceStatus(hServiceStatus, &SvcStatus);
+}
+
+static
+DWORD
+WINAPI
+ServiceControlHandler(
+    DWORD dwControl,
+    DWORD dwEventType,
+    LPVOID lpEventData,
+    LPVOID lpContext)
+{
+    switch (dwControl)
+    {
+        case SERVICE_CONTROL_SHUTDOWN:
+        case SERVICE_CONTROL_STOP:
+            UpdateServiceStatus(ServiceStatusHandle, SERVICE_STOP_PENDING, 1);
+            RpcMgmtStopServerListening(NULL);
+            DnsIntCacheFree();
+            UpdateServiceStatus(ServiceStatusHandle, SERVICE_STOPPED, 0);
+            break;
+
+        case SERVICE_CONTROL_INTERROGATE:
+            return NO_ERROR;
+
+        default:
+            return ERROR_CALL_NOT_IMPLEMENTED;
+    }
+    return NO_ERROR;
+}
+
+VOID
+WINAPI
+ServiceMain(
+    DWORD argc,
+    LPWSTR *argv)
+{
+    HANDLE hThread;
+
+    UNREFERENCED_PARAMETER(argc);
+    UNREFERENCED_PARAMETER(argv);
+
+    DPRINT("ServiceMain() called\n");
+
+    SvcStatus.dwServiceType             = SERVICE_WIN32_OWN_PROCESS;
+    SvcStatus.dwCurrentState            = SERVICE_START_PENDING;
+    SvcStatus.dwControlsAccepted        = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+    SvcStatus.dwCheckPoint              = 0;
+    SvcStatus.dwWin32ExitCode           = NO_ERROR;
+    SvcStatus.dwServiceSpecificExitCode = 0;
+    SvcStatus.dwWaitHint                = 4000;
+
+    ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
+                                                        ServiceControlHandler,
+                                                        NULL);
+
+    if (!ServiceStatusHandle)
+    {
+        DPRINT1("DNSRSLVR: Unable to register service control handler (%lx)\n", GetLastError());
+        return; // FALSE
+    }
+
+    DnsIntCacheInitialize();
+
+    hThread = CreateThread(NULL,
+                           0,
+                           (LPTHREAD_START_ROUTINE)
+                           RpcThreadRoutine,
+                           NULL,
+                           0,
+                           NULL);
+
+    if (!hThread)
+    {
+        DnsIntCacheFree();
+        DPRINT("Can't create RpcThread\n");
+        UpdateServiceStatus(ServiceStatusHandle, SERVICE_STOPPED, 0);
+    }
+    else
+    {
+        CloseHandle(hThread);
+    }
+
+    DPRINT("ServiceMain() done\n");
+    UpdateServiceStatus(ServiceStatusHandle, SERVICE_RUNNING, 0);
+}
+
+BOOL
+WINAPI
+DllMain(
+    _In_ HINSTANCE hinstDLL,
+    _In_ DWORD fdwReason,
+    _In_ PVOID pvReserved)
+{
+    UNREFERENCED_PARAMETER(pvReserved);
+
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls(hinstDLL);
+            hDllInstance = hinstDLL;
+            break;
+
+        case DLL_PROCESS_DETACH:
+            break;
+    }
+
+    return TRUE;
+}
+
+/* EOF */
diff --git a/base/services/dnsrslvr/dnsrslvr.rc b/base/services/dnsrslvr/dnsrslvr.rc
new file mode 100644 (file)
index 0000000..482aefe
--- /dev/null
@@ -0,0 +1,4 @@
+#define REACTOS_STR_FILE_DESCRIPTION  "DNS-Client"
+#define REACTOS_STR_INTERNAL_NAME     "dnsrslvr"
+#define REACTOS_STR_ORIGINAL_FILENAME "dnsrslvr.dll"
+#include <reactos/version.rc>
diff --git a/base/services/dnsrslvr/dnsrslvr.spec b/base/services/dnsrslvr/dnsrslvr.spec
new file mode 100644 (file)
index 0000000..1b27fe5
--- /dev/null
@@ -0,0 +1 @@
+@ stdcall ServiceMain(long ptr)
diff --git a/base/services/dnsrslvr/precomp.h b/base/services/dnsrslvr/precomp.h
new file mode 100644 (file)
index 0000000..0a11db5
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _DNSRSLVR_PCH_
+#define _DNSRSLVR_PCH_
+
+#include <stdarg.h>
+
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+
+#include <windef.h>
+#include <winbase.h>
+#include <winsvc.h>
+#include <windns.h>
+
+#include <ndk/rtlfuncs.h>
+#include <ndk/obfuncs.h>
+
+#include <dnsrslvr_s.h>
+
+typedef struct _RESOLVER_CACHE_ENTRY
+{
+    LIST_ENTRY CacheLink;
+    PDNS_RECORDW Record;
+} RESOLVER_CACHE_ENTRY, *PRESOLVER_CACHE_ENTRY;
+
+typedef struct _RESOLVER_CACHE
+{
+    LIST_ENTRY RecordList;
+    CRITICAL_SECTION Lock;
+} RESOLVER_CACHE, *PRESOLVER_CACHE;
+
+
+/* cache.c */
+
+VOID DnsIntCacheInitialize(VOID);
+VOID DnsIntCacheRemoveEntryItem(PRESOLVER_CACHE_ENTRY CacheEntry);
+VOID DnsIntCacheFree(VOID);
+VOID DnsIntCacheFlush(VOID);
+BOOL DnsIntCacheGetEntryFromName(LPCWSTR Name,
+                                 PDNS_RECORDW *Record);
+VOID DnsIntCacheAddEntry(PDNS_RECORDW Record);
+BOOL DnsIntCacheRemoveEntryByName(LPCWSTR Name);
+
+
+#endif /* _DNSRSLVR_PCH_ */
diff --git a/base/services/dnsrslvr/rpcserver.c b/base/services/dnsrslvr/rpcserver.c
new file mode 100644 (file)
index 0000000..0cb5c1f
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * PROJECT:     ReactOS DNS Resolver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        base/services/dnsrslvr/rpcserver.c
+ * PURPOSE:     RPC server interface
+ * COPYRIGHT:   Copyright 2016 Christoph von Wittich
+ */
+
+#include "precomp.h"
+
+#define NDEBUG
+#include <debug.h>
+
+DWORD
+WINAPI
+RpcThreadRoutine(LPVOID lpParameter)
+{
+    RPC_STATUS Status;
+
+    Status = RpcServerUseProtseqEpW(L"ncalrpc", 20, L"DNSResolver", NULL);
+    if (Status != RPC_S_OK)
+    {
+        DPRINT("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
+        return 0;
+    }
+
+    Status = RpcServerRegisterIf(DnsResolver_v2_0_s_ifspec, NULL, NULL);
+    if (Status != RPC_S_OK)
+    {
+        DPRINT("RpcServerRegisterIf() failed (Status %lx)\n", Status);
+        return 0;
+    }
+
+    Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, 0);
+    if (Status != RPC_S_OK)
+    {
+        DPRINT("RpcServerListen() failed (Status %lx)\n", Status);
+    }
+
+    DPRINT("RpcServerListen finished\n");
+    return 0;
+}
+
+DWORD
+R_ResolverFlushCache(
+    DNSRSLVR_HANDLE pwszServerName)
+{
+    // FIXME Should store (and flush) entries by server handle
+    DnsIntCacheFlush();
+    return 0;
+}
+
+DWORD
+R_ResolverQuery(
+    DNSRSLVR_HANDLE pwszServerName,
+    LPCWSTR pwsName,
+    WORD wType,
+    DWORD Flags,
+    DWORD *dwRecords,
+    DNS_RECORDW **ppResultRecords)
+{
+#if 0
+    DNS_QUERY_REQUEST  QueryRequest = { 0 };
+    DNS_QUERY_RESULT   QueryResults = { 0 };
+#endif
+    DNS_STATUS         Status;
+    PDNS_RECORDW       Record;
+
+    DPRINT1("R_ResolverQuery %p %p %x %lx %p %p\n",
+            pwszServerName, pwsName, wType, Flags, dwRecords, ppResultRecords);
+
+    if (!pwszServerName || !pwsName || !wType || !ppResultRecords)
+        return ERROR_INVALID_PARAMETER;
+
+    // FIXME Should lookup entries by server handle
+    if (DnsIntCacheGetEntryFromName(pwsName, ppResultRecords))
+    {
+        Status = ERROR_SUCCESS;
+    }
+    else
+    {
+#if 0
+        QueryRequest.Version = DNS_QUERY_REQUEST_VERSION1;
+        QueryRequest.QueryType = wType;
+        QueryRequest.QueryName = pwsName;
+        QueryRequest.QueryOptions = Flags;
+        QueryResults.Version = DNS_QUERY_REQUEST_VERSION1;
+
+        Status = DnsQueryEx(&QueryRequest, &QueryResults, NULL);
+        if (Status == ERROR_SUCCESS)
+        {
+            // FIXME Should store (and flush) entries by server handle
+            DnsIntCacheAddEntry(QueryResults.pQueryRecords);
+            *ppResultRecords = QueryResults.pQueryRecords;
+        }
+#endif
+    }
+
+    if (dwRecords)
+        *dwRecords = 0;
+
+    if (Status == ERROR_SUCCESS)
+    {
+        Record = *ppResultRecords;
+        while (Record)
+        {
+            if (dwRecords)
+                (*dwRecords)++;
+            Record = Record->pNext;
+        }
+    }
+
+    DPRINT1("R_ResolverQuery result %ld %ld\n", Status, *dwRecords);
+
+    return Status;
+}
+
+void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
+{
+    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+}
+
+void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
+{
+    HeapFree(GetProcessHeap(), 0, ptr);
+}
+
+void __RPC_USER WLANSVC_RPC_HANDLE_rundown(DNSRSLVR_HANDLE hClientHandle)
+{
+}
index eaf1b7c..d179e9d 100644 (file)
@@ -27,7 +27,7 @@ AddReg = TCPIP_AddReg_Global.NT
 HKR,"Ndi","ClsId",0x00000000,"{A907657F-6FDF-11D0-8EFB-00C04FD912B2}"
 HKR,"Ndi","HelpText",0x00000000,"Transmission Control Protocol/Internet Protocol"
 HKR,"Ndi","Service",0x00000000,"Tcpip"
-HKR,"Ndi","CoServices",0x00010000,"Tcpip","Dhcp"
+HKR,"Ndi","CoServices",0x00010000,"Tcpip","Dhcp","Dnscache"
 
 ; TCP/IPv4 driver
 ; NOTE: These settings should be added by the network setup
@@ -236,6 +236,7 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Winsock2\Parameters\Protocol_Catalog9\Ca
 [MS_TCPIP.PrimaryInstall.Services]
 AddService = Tcpip, , tcpip_Service_Inst
 AddService = DHCP, , dhcp_Service_Inst
+AddService = Dnscache, , dns_Service_Inst
 
 [tcpip_Service_Inst]
 ServiceType   = 1
@@ -275,6 +276,20 @@ AddReg=dhcp_AddReg
 HKR,,"ObjectName",0x00000000,"LocalSystem"
 HKR,"Parameters","ServiceDll",0x00020000,"%SystemRoot%\system32\dhcpcsvc.dll"
 
+[dns_Service_Inst]
+DisplayName   = "DNS Client"
+Description   = "Service that caches local DNS queries"
+ServiceType   = 0x20
+StartType     = 2
+ErrorControl  = 1
+ServiceBinary = "%11%\svchost.exe -k netsvcs"
+LoadOrderGroup = TDI
+AddReg=dns_AddReg
+
+[dns_AddReg]
+HKR,,"ObjectName",0x00000000,"LocalSystem"
+HKR,"Parameters","ServiceDll",0x00020000,"%SystemRoot%\system32\dnsrslvr.dll"
+
 ;-------------------------------- STRINGS -------------------------------
 
 [Strings]
index ee5af55..787e5c7 100644 (file)
@@ -6,7 +6,10 @@
 
 #define UNICODE
 #include <sal.h>
+
+cpp_quote("#ifndef _WINDNS_INCLUDED_")
 #include <windns.h>
+cpp_quote("#endif")
 
 typedef [handle, string] LPWSTR DNSRSLVR_HANDLE;
 
index 3af80a1..01e6f41 100644 (file)
@@ -14,6 +14,10 @@ typedef struct _DNS_CACHE_ENTRY
     unsigned short wFlags;          /* DNS Record Flags */
 } DNS_CACHE_ENTRY, *PDNS_CACHE_ENTRY;
 
+
+#ifndef __WIDL__
+// Hack
+
 BOOL
 WINAPI
 DnsFlushResolverCache(VOID);
@@ -23,6 +27,8 @@ WINAPI
 DnsGetCacheDataTable(
     _Out_ PDNS_CACHE_ENTRY *DnsCache);
 
+#endif /* __WIDL__ */
+
 #ifdef __cplusplus
 }
 #endif