+struct dll_sym {
+ void **func_ptr;
+ const char *name;
+ bool required;
+};
+
+#define DLL_SYM(name, required) { (void **)&func_##name, #name, required }
+
+#define for_each_sym(sym, spec) \
+ for ((sym) = (spec)->syms; (sym)->name; (sym)++)
+
+struct dll_spec {
+ const wchar_t *name;
+ HMODULE handle;
+ const struct dll_sym syms[];
+};
+
+struct dll_spec ntdll_spec = {
+ .name = L"ntdll.dll",
+ .syms = {
+ DLL_SYM(NtOpenFile, true),
+ DLL_SYM(NtReadFile, true),
+ DLL_SYM(NtQueryInformationFile, true),
+ DLL_SYM(NtQuerySecurityObject, true),
+ DLL_SYM(NtQueryDirectoryFile, true),
+ DLL_SYM(NtQueryVolumeInformationFile, true),
+ DLL_SYM(NtSetSecurityObject, true),
+ DLL_SYM(NtClose, true),
+ DLL_SYM(RtlNtStatusToDosError, true),
+ DLL_SYM(RtlCreateSystemVolumeInformationFolder, false),
+ {NULL, NULL},
+ },
+};
+
+struct dll_spec kernel32_spec = {
+ .name = L"kernel32.dll",
+ .syms = {
+ DLL_SYM(CreateSymbolicLinkW, false),
+ {NULL, NULL},
+ },
+};
+
+static int
+init_dll(struct dll_spec *spec)
+{
+ const struct dll_sym *sym;
+ void *addr;
+
+ if (!spec->handle)
+ spec->handle = LoadLibrary(spec->name);
+ if (!spec->handle) {
+ for_each_sym(sym, spec) {
+ if (sym->required) {
+ ERROR("%ls could not be loaded!", spec->name);
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+ }
+ return 0;
+ }
+ for_each_sym(sym, spec) {
+ addr = (void *)GetProcAddress(spec->handle, sym->name);
+ if (addr) {
+ *(sym->func_ptr) = addr;
+ } else if (sym->required) {
+ ERROR("Can't find %s in %ls", sym->name, spec->name);
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+ }
+ return 0;
+}
+
+static void
+cleanup_dll(struct dll_spec *spec)
+{
+ const struct dll_sym *sym;
+
+ if (spec->handle) {
+ FreeLibrary(spec->handle);
+ spec->handle = NULL;
+
+ for_each_sym(sym, spec)
+ *(sym->func_ptr) = NULL;
+ }
+}
+