+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
+{
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ NTSTATUS Status;
+ BOOLEAN LockHeld;
+ ULONG_PTR Cookie;
+ DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
+
+ /* Don't do it during shutdown */
+ if (LdrpShutdownInProgress) return STATUS_SUCCESS;
+
+ /* Check if we should grab the lock */
+ LockHeld = FALSE;
+ if (!LdrpInLdrInit)
+ {
+ /* Grab the lock */
+ Status = LdrLockLoaderLock(0, NULL, &Cookie);
+ if (!NT_SUCCESS(Status)) return Status;
+ LockHeld = TRUE;
+ }
+
+ /* Make sure the DLL is valid and get its entry */
+ Status = STATUS_DLL_NOT_FOUND;
+ if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
+ {
+ /* Get if it has a TLS slot */
+ if (!LdrEntry->TlsIndex)
+ {
+ /* It doesn't, so you're allowed to call this */
+ LdrEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS;
+ Status = STATUS_SUCCESS;
+ }
+ }
+
+ /* Check if the lock was held */
+ if (LockHeld)
+ {
+ /* Release it */
+ LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
+ }
+
+ /* Return the status */
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrAddRefDll(IN ULONG Flags,
+ IN PVOID BaseAddress)
+{
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG Cookie;
+ BOOLEAN Locked = FALSE;
+
+ /* Check for invalid flags */
+ if (Flags & ~(LDR_ADDREF_DLL_PIN))
+ {
+ /* Fail with invalid parameter status if so */
+ Status = STATUS_INVALID_PARAMETER;
+ goto quickie;
+ }
+
+ /* Acquire the loader lock if not in init phase */
+ if (!LdrpInLdrInit)
+ {
+ /* Acquire the lock */
+ Status = LdrLockLoaderLock(0, NULL, &Cookie);
+ if (!NT_SUCCESS(Status)) goto quickie;
+ Locked = TRUE;
+ }
+
+ /* Get this module's data table entry */
+ if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
+ {
+ if (!LdrEntry)
+ {
+ /* Shouldn't happen */
+ Status = STATUS_INTERNAL_ERROR;
+ goto quickie;
+ }
+
+ /* If this is not a pinned module */
+ if (LdrEntry->LoadCount != 0xFFFF)
+ {
+ /* Update its load count */
+ if (Flags & LDR_ADDREF_DLL_PIN)
+ {
+ /* Pin it by setting load count to -1 */
+ LdrEntry->LoadCount = 0xFFFF;
+ LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_PIN);
+ }
+ else
+ {
+ /* Increase its load count by one */
+ LdrEntry->LoadCount++;
+ LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT);
+ }
+
+ /* Clear load in progress */
+ LdrpClearLoadInProgress();
+ }
+ }
+ else
+ {
+ /* There was an error getting this module's handle, return invalid param status */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+quickie:
+ /* Check for error case */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Print debug information */
+ if ((ShowSnaps) || ((Status != STATUS_NO_SUCH_FILE) &&
+ (Status != STATUS_DLL_NOT_FOUND) &&
+ (Status != STATUS_OBJECT_NAME_NOT_FOUND)))
+ {
+ DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress);
+ }
+ }
+
+ /* Release the lock if needed */
+ if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrUnloadDll(IN PVOID BaseAddress)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PPEB Peb = NtCurrentPeb();
+ PLDR_DATA_TABLE_ENTRY LdrEntry, CurrentEntry;
+ PVOID EntryPoint;
+ PLIST_ENTRY NextEntry;
+ LIST_ENTRY UnloadList;
+ RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
+ PVOID CorImageData;
+ ULONG ComSectionSize;
+
+ /* Get the LDR Lock */
+ if (!LdrpInLdrInit) RtlEnterCriticalSection(Peb->LoaderLock);
+
+ /* Increase the unload count */
+ LdrpActiveUnloadCount++;
+
+ /* Skip unload */
+ if (LdrpShutdownInProgress) goto Quickie;
+
+ /* Make sure the DLL is valid and get its entry */
+ if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
+ {
+ Status = STATUS_DLL_NOT_FOUND;
+ goto Quickie;
+ }
+
+ /* Check the current Load Count */
+ if (LdrEntry->LoadCount != 0xFFFF)
+ {
+ /* Decrease it */
+ LdrEntry->LoadCount--;
+
+ /* If it's a dll */
+ if (LdrEntry->Flags & LDRP_IMAGE_DLL)
+ {
+ /* Set up the Act Ctx */
+ ActCtx.Size = sizeof(ActCtx);
+ ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
+ RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
+
+ /* Activate the ActCtx */
+ RtlActivateActivationContextUnsafeFast(&ActCtx,
+ LdrEntry->EntryPointActivationContext);
+
+ /* Update the load count */
+ LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_DEREFCOUNT);
+
+ /* Release the context */
+ RtlDeactivateActivationContextUnsafeFast(&ActCtx);
+ }
+ }
+ else
+ {
+ /* The DLL is locked */
+ goto Quickie;
+ }
+
+ /* Show debug message */
+ if (ShowSnaps) DPRINT1("LDR: UNINIT LIST\n");
+
+ /* Check if this is our only unload and initialize the list if so */
+ if (LdrpActiveUnloadCount == 1) InitializeListHead(&LdrpUnloadHead);
+
+ /* Loop the modules to build the list */
+ NextEntry = Peb->Ldr->InInitializationOrderModuleList.Blink;
+ while (NextEntry != &Peb->Ldr->InInitializationOrderModuleList)
+ {
+ /* Get the entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InInitializationOrderModuleList);
+ NextEntry = NextEntry->Blink;
+
+ /* Remove flag */
+ LdrEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS;
+
+ /* If the load count is now 0 */
+ if (!LdrEntry->LoadCount)
+ {
+ /* Show message */
+ if (ShowSnaps)
+ {
+ DPRINT1("(%d) [%ws] %ws (%lx) deinit %lx\n",
+ LdrpActiveUnloadCount,
+ LdrEntry->BaseDllName.Buffer,
+ LdrEntry->FullDllName.Buffer,
+ (ULONG)LdrEntry->LoadCount,
+ LdrEntry->EntryPoint);
+ }
+
+ /* FIXME: Call Shim Engine and notify */
+
+ /* Unlink it */
+ CurrentEntry = LdrEntry;
+ RemoveEntryList(&CurrentEntry->InInitializationOrderModuleList);
+ RemoveEntryList(&CurrentEntry->InMemoryOrderModuleList);
+ RemoveEntryList(&CurrentEntry->HashLinks);
+
+ /* If there's more then one active unload */
+ if (LdrpActiveUnloadCount > 1)
+ {
+ /* Flush the cached DLL handle and clear the list */
+ LdrpLoadedDllHandleCache = NULL;
+ CurrentEntry->InMemoryOrderModuleList.Flink = NULL;
+ }
+
+ /* Add the entry on the unload list */
+ InsertTailList(&LdrpUnloadHead, &CurrentEntry->HashLinks);
+ }
+ }
+
+ /* Only call the entrypoints once */
+ if (LdrpActiveUnloadCount > 1) goto Quickie;
+
+ /* Now loop the unload list and create our own */
+ InitializeListHead(&UnloadList);
+ CurrentEntry = NULL;
+ NextEntry = LdrpUnloadHead.Flink;
+ while (NextEntry != &LdrpUnloadHead)
+ {
+ /* If we have an active entry */
+ if (CurrentEntry)
+ {
+ /* Remove it */
+ RemoveEntryList(&CurrentEntry->InLoadOrderLinks);
+ CurrentEntry = NULL;
+
+ /* Reset list pointers */
+ NextEntry = LdrpUnloadHead.Flink;
+ if (NextEntry == &LdrpUnloadHead) break;
+ }
+
+ /* Get the current entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
+
+ /* FIXME: Log the Unload Event */
+ //LdrpRecordUnloadEvent(LdrEntry);
+
+ /* Set the entry and clear it from the list */
+ CurrentEntry = LdrEntry;
+ LdrpLoadedDllHandleCache = NULL;
+ CurrentEntry->InMemoryOrderModuleList.Flink = NULL;
+
+ /* Move it from the global to the local list */
+ RemoveEntryList(&CurrentEntry->HashLinks);
+ InsertTailList(&UnloadList, &CurrentEntry->HashLinks);
+
+ /* Get the entrypoint */
+ EntryPoint = LdrEntry->EntryPoint;
+
+ /* Check if we should call it */
+ if ((EntryPoint) && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED))
+ {
+ /* Show message */
+ if (ShowSnaps)
+ {
+ DPRINT1("LDR: Calling deinit %lx\n", EntryPoint);
+ }
+
+ /* Set up the Act Ctx */
+ ActCtx.Size = sizeof(ActCtx);
+ ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
+ RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
+
+ /* Activate the ActCtx */
+ RtlActivateActivationContextUnsafeFast(&ActCtx,
+ LdrEntry->EntryPointActivationContext);
+
+ /* Call the entrypoint */
+ LdrpCallInitRoutine(LdrEntry->EntryPoint,
+ LdrEntry->DllBase,
+ DLL_PROCESS_DETACH,
+ NULL);
+
+ /* Release the context */
+ RtlDeactivateActivationContextUnsafeFast(&ActCtx);
+ }
+
+ /* Remove it from the list */
+ RemoveEntryList(&CurrentEntry->InLoadOrderLinks);
+ CurrentEntry = NULL;
+ NextEntry = LdrpUnloadHead.Flink;
+ }
+
+ /* Now loop our local list */
+ NextEntry = UnloadList.Flink;
+ while (NextEntry != &UnloadList)
+ {
+ /* Get the entry */
+ LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
+ NextEntry = NextEntry->Flink;
+ CurrentEntry = LdrEntry;
+
+ /* Notify Application Verifier */
+ if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
+ {
+ DPRINT1("We don't support Application Verifier yet\n");
+ }
+
+ /* Show message */
+ if (ShowSnaps)
+ {
+ DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry->BaseDllName.Buffer);
+ }
+
+ /* Check if this is a .NET executable */
+ CorImageData = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
+ &ComSectionSize);
+ if (CorImageData)
+ {
+ /* FIXME */
+ DPRINT1(".NET Images are not supported yet\n");
+ }
+
+ /* Check if we should unmap*/
+ if (!(CurrentEntry->Flags & LDR_COR_OWNS_UNMAP))
+ {
+ /* Unmap the DLL */
+ Status = NtUnmapViewOfSection(NtCurrentProcess(),
+ CurrentEntry->DllBase);
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* Unload the alternate resource module, if any */
+ LdrUnloadAlternateResourceModule(CurrentEntry->DllBase);
+
+ /* FIXME: Send shutdown notification */
+ //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
+
+ /* Check if a Hotpatch is active */
+ if (LdrEntry->PatchInformation)
+ {
+ /* FIXME */
+ DPRINT1("We don't support Hotpatching yet\n");
+ }
+
+ /* Deallocate the Entry */
+ LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry);
+
+ /* If this is the cached entry, invalidate it */
+ if (LdrpGetModuleHandleCache == CurrentEntry)
+ {
+ LdrpGetModuleHandleCache = NULL;
+ }
+ }
+
+Quickie:
+ /* Decrease unload count */
+ LdrpActiveUnloadCount--;
+ if (!LdrpInLdrInit) RtlLeaveCriticalSection(Peb->LoaderLock);
+
+ /* Return to caller */
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+RtlDllShutdownInProgress(VOID)
+{
+ /* Return the internal global */
+ return LdrpShutdownInProgress;
+}
+
+/*
+ * @implemented
+ */
+PIMAGE_BASE_RELOCATION
+NTAPI
+LdrProcessRelocationBlock(IN ULONG_PTR Address,
+ IN ULONG Count,
+ IN PUSHORT TypeOffset,
+ IN LONG_PTR Delta)
+{
+ return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta);
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
+{
+ static BOOLEAN WarnedOnce = FALSE;
+ if (WarnedOnce == FALSE) { UNIMPLEMENTED; WarnedOnce = TRUE; }
+ return FALSE;
+}
+