Skip to content

Commit 4dc8a52

Browse files
committed
Merge remote-tracking branch 'origin/feature/texmod-setfiles-sorting' into dev
2 parents f84645a + db6445f commit 4dc8a52

1 file changed

Lines changed: 47 additions & 8 deletions

File tree

GWToolboxdll/Modules/TexmodModule.cpp

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,19 @@ namespace {
8989
// =========================================================================
9090

9191
HMODULE gmodDll = nullptr;
92+
// True only when this module called LoadLibrary on gmodDll, i.e. we own the
93+
// reference and must FreeLibrary it on teardown. False when gMod was already
94+
// present (e.g. injected as the d3d9.dll proxy) - that copy belongs to the game.
95+
bool gmodLoadedByUs = false;
9296

9397
std::vector<TexturePackEntry> packs;
9498

9599
bool gmodReady = false;
96100
std::string statusMessage;
97101
bool gmodLoadAttempted = false;
102+
// Set when gMod is no longer needed (last pack removed); the unload is performed
103+
// from Update() rather than the draw pass.
104+
bool gmodUnloadRequested = false;
98105

99106
constexpr const char* INI_SECTION = "TexmodModule";
100107
constexpr const char* INI_PACK_COUNT = "PackCount";
@@ -324,6 +331,7 @@ namespace {
324331
HMODULE h = GetModuleHandleW(name);
325332
if (!h) continue;
326333
gmodDll = h;
334+
gmodLoadedByUs = false; // already in the process; we don't own this reference
327335
if (!ResolveTextureClientFunctions()) {
328336
gmodDll = nullptr;
329337
continue;
@@ -335,6 +343,12 @@ namespace {
335343
return true;
336344
}
337345

346+
// Only load our own copy of gMod when there is a pack to serve. With no packs
347+
// there is nothing to mod, so we leave gMod unloaded rather than have it hook
348+
// the device for nothing. (A gMod already injected as the d3d9 proxy was
349+
// adopted above regardless of this.)
350+
if (packs.empty()) return false;
351+
338352
if (gmodLoadAttempted) {
339353
// statusMessage = "Error: gMod initialization already attempted and failed. Please fix the issue and click Retry.";
340354
return false;
@@ -352,11 +366,13 @@ namespace {
352366
statusMessage = "Error: Could not load gMod.dll. Make sure it is next to GWToolbox.dll.";
353367
return false;
354368
}
369+
gmodLoadedByUs = true; // we own this reference and must FreeLibrary it on teardown
355370

356371
// 3. Resolve TextureClient shim exports.
357372
if (!ResolveTextureClientFunctions()) {
358373
FreeLibrary(gmodDll);
359374
gmodDll = nullptr;
375+
gmodLoadedByUs = false;
360376
return false;
361377
}
362378
pfnSetDevice(GuildWars_IDirect3DDevice9_Instance);
@@ -479,13 +495,11 @@ namespace {
479495

480496
void ShutdownGMod()
481497
{
482-
if (!gmodReady) return;
483-
484-
// Unload synchronously: on teardown the worker threads are stopping, so a
485-
// queued ApplyLoadOrder might never run. Holding apply_mutex waits out any
486-
// in-flight worker reconcile; bumping the generation makes queued/running
487-
// ones skip; then we remove everything here, last, so nothing reloads after.
488-
{
498+
if (gmodReady) {
499+
// Unload synchronously: on teardown the worker threads are stopping, so a
500+
// queued ApplyLoadOrder might never run. Holding apply_mutex waits out any
501+
// in-flight worker reconcile; bumping the generation makes queued/running
502+
// ones skip; then we remove everything here, last, so nothing reloads after.
489503
std::lock_guard lk(apply_mutex);
490504
++apply_generation;
491505
for (auto& pack : packs)
@@ -497,6 +511,21 @@ namespace {
497511
}
498512

499513
gmodReady = false;
514+
pfnAddFile = nullptr;
515+
pfnRemoveFile = nullptr;
516+
pfnGetFiles = nullptr;
517+
pfnSetDevice = nullptr;
518+
519+
// Free the dll only if we loaded it. gMod's DllMain(DLL_PROCESS_DETACH) reverts
520+
// all its D3D9 vtable hooks (RemoveAllD3D9Hooks), so this is its clean shutdown
521+
// path. A gMod injected as the d3d9 proxy is owned by the game - never free it.
522+
if (gmodLoadedByUs && gmodDll) {
523+
FreeLibrary(gmodDll);
524+
}
525+
gmodDll = nullptr;
526+
gmodLoadedByUs = false;
527+
gmodLoadAttempted = false; // allow a fresh load later (e.g. when a pack is added)
528+
gmodLocalVersionChecked = false;
500529
}
501530

502531
// =========================================================================
@@ -856,6 +885,8 @@ namespace {
856885
if (ImGui::ConfirmButton(ICON_FA_TRASH, &del_bool)) {
857886
if (pack.loaded) UnloadTexturePack(pack.path);
858887
packs.erase(packs.begin() + i);
888+
// No packs left to serve: drop gMod so it stops hooking the device.
889+
if (packs.empty()) gmodUnloadRequested = true;
859890
ImGui::PopID();
860891
break;
861892
}
@@ -1142,6 +1173,14 @@ void TexmodModule::Update(float)
11421173
// Keep the D3D9 CreateTexture capture hook matched to the recording toggle.
11431174
SetTextureCapture(recording);
11441175

1176+
// Unload gMod once nothing needs it (requested when the last pack was removed).
1177+
if (gmodUnloadRequested) {
1178+
gmodUnloadRequested = false;
1179+
// Only unload what we own; an injected proxy is left to the game. ShutdownGMod
1180+
// already no-ops the FreeLibrary in that case, but skip the pack teardown too.
1181+
if (gmodLoadedByUs) ShutdownGMod();
1182+
}
1183+
11451184
if (gmodReady) return;
11461185
InitGMod();
11471186
}
@@ -1154,7 +1193,7 @@ void TexmodModule::Draw(IDirect3DDevice9*)
11541193
void TexmodModule::Terminate()
11551194
{
11561195
TeardownTextureCapture();
1157-
ShutdownGMod(); // synchronously unloads every pack from gMod
1196+
ShutdownGMod(); // unloads every pack and frees gMod.dll if we loaded it
11581197
ToolboxModule::Terminate();
11591198
}
11601199

0 commit comments

Comments
 (0)