+#ifdef _WIN32
+ /*
+ * We need to look for wpcap.dll in \Windows\System32\Npcap first,
+ * as either:
+ *
+ * 1) WinPcap isn't installed and Npcap isn't installed in "WinPcap
+ * API-compatible Mode", so there's no wpcap.dll in
+ * \Windows\System32, only in \Windows\System32\Npcap;
+ *
+ * 2) WinPcap is installed and Npcap isn't installed in "WinPcap
+ * API-compatible Mode", so the wpcap.dll in \Windows\System32
+ * is a WinPcap DLL, but we'd prefer an Npcap DLL (we should
+ * work with either one if we're configured against WinPcap,
+ * and we'll probably require Npcap if we're configured against
+ * it), and that's in \Windows\System32\Npcap;
+ *
+ * 3) Npcap is installed in "WinPcap API-compatible Mode", so both
+ * \Windows\System32 and \Windows\System32\Npcap have an Npcap
+ * wpcap.dll.
+ *
+ * Unfortunately, Windows has no notion of an rpath, so we can't
+ * set the rpath to include \Windows\System32\Npcap at link time;
+ * what we need to do is to link wpcap as a delay-load DLL and
+ * add \Windows\System32\Npcap to the DLL search path early in
+ * main() with a call to SetDllDirectory().
+ *
+ * The same applies to packet.dll.
+ *
+ * We add \Windows\System32\Npcap here.
+ *
+ * See https://npcap.com/guide/npcap-devguide.html#npcap-feature-native-dll-implicitly
+ */
+ WCHAR *dll_directory = NULL;
+ size_t dll_directory_buf_len = 0; /* units of bytes */
+ UINT system_directory_buf_len = 0; /* units of WCHARs */
+ UINT system_directory_len; /* units of WCHARs */
+ static const WCHAR npcap[] = L"\\Npcap";
+
+ /*
+ * Get the system directory path, in UTF-16, into a buffer that's
+ * large enough for that directory path plus "\Npcap".
+ *
+ * String manipulation in C, plus fetching a variable-length
+ * string into a buffer whose size is fixed at the time of
+ * the call, with an oddball return value (see below), is just
+ * a huge bag of fun.
+ *
+ * And it's even more fun when dealing with UTF-16, so that the
+ * buffer sizes used in GetSystemDirectoryW() are in different
+ * units from the buffer sizes used in realloc()! We maintain
+ * all sizes/length in units of bytes, not WCHARs, so that our
+ * heads don't explode.
+ */
+ for (;;) {
+ /*
+ * Try to fetch the system directory.
+ *
+ * GetSystemDirectoryW() expects a buffer size in units
+ * of WCHARs, not bytes, and returns a directory path
+ * length in units of WCHARs, not bytes.
+ *
+ * For extra fun, if GetSystemDirectoryW() succeeds,
+ * the return value is the length of the directory
+ * path in units of WCHARs, *not* including the
+ * terminating '\0', but if it fails because the
+ * path string wouldn't fit, the return value is
+ * the length of the directory path in units of WCHARs,
+ * *including* the terminating '\0'.
+ */
+ system_directory_len = GetSystemDirectoryW(dll_directory,
+ system_directory_buf_len);
+ if (system_directory_len == 0)
+ error("GetSystemDirectoryW() failed");
+
+ /*
+ * Did the directory path fit in the buffer?
+ *
+ * As per the above, this means that the return value
+ * *plus 1*, so that the terminating '\0' is counted,
+ * is <= the buffer size.
+ *
+ * (If the directory path, complete with the terminating
+ * '\0', fits *exactly*, the return value would be the
+ * size of the buffer minus 1, as it doesn't count the
+ * terminating '\0', so the test below would succeed.
+ *
+ * If everything *but* the terminating '\0' fits,
+ * the return value would be the size of the buffer + 1,
+ * i.e., the size that the string in question would
+ * have required.
+ *
+ * The astute reader will note that returning the
+ * size of the buffer is not one of the two cases
+ * above, and should never happen.)
+ */
+ if ((system_directory_len + 1) <= system_directory_buf_len) {
+ /*
+ * No. We have a buffer that's large enough
+ * for our purposes.
+ */
+ break;
+ }
+
+ /*
+ * Yes. Grow the buffer.
+ *
+ * The space we'll need in the buffer for the system
+ * directory, in units of WCHARs, is system_directory_len,
+ * as that's the length of the system directory path
+ * including the terminating '\0'.
+ */
+ system_directory_buf_len = system_directory_len;
+
+ /*
+ * The size of the DLL directory buffer, in *bytes*, must
+ * be the number of WCHARs taken by the system directory,
+ * *minus* the terminating '\0' (as we'll overwrite that
+ * with the "\" of the "\Npcap" string), multiplied by
+ * sizeof(WCHAR) to convert it to the number of bytes,
+ * plus the size of the "\Npcap" string, in bytes (which
+ * will include the terminating '\0', as that will become
+ * the DLL path's terminating '\0').
+ */
+ dll_directory_buf_len =
+ ((system_directory_len - 1)*sizeof(WCHAR)) + sizeof npcap;
+ dll_directory = realloc(dll_directory, dll_directory_buf_len);
+ if (dll_directory == NULL)
+ error("Can't allocate string for Npcap directory");
+ }
+
+ /*
+ * OK, that worked.
+ *
+ * Now append \Npcap. We add the length of the system directory path,
+ * in WCHARs, *not* including the terminating '\0' (which, since
+ * GetSystemDirectoryW() succeeded, is the return value of
+ * GetSystemDirectoryW(), as per the above), to the pointer to the
+ * beginning of the path, to go past the end of the system directory
+ * to point to the terminating '\0'.
+ */
+ memcpy(dll_directory + system_directory_len, npcap, sizeof npcap);
+
+ /*
+ * Now add that as a system DLL directory.
+ */
+ if (!SetDllDirectoryW(dll_directory))
+ error("SetDllDirectory failed");
+
+ free(dll_directory);
+#endif // _WIN32
+