From 02f23141395d5407302cc695374079320ac4c92e Mon Sep 17 00:00:00 2001 From: Alex Mendoza <05alex.mendozaa@gmail.com> Date: Sat, 27 Jun 2026 16:36:29 +0200 Subject: [PATCH] [SHELL32] Implement LockServer (#9055) --- dll/win32/shell32/shell32.cpp | 30 ++++++++- .../rostests/apitests/shell32/CMakeLists.txt | 1 + .../rostests/apitests/shell32/LockServer.cpp | 66 +++++++++++++++++++ modules/rostests/apitests/shell32/testlist.c | 2 + 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 modules/rostests/apitests/shell32/LockServer.cpp diff --git a/dll/win32/shell32/shell32.cpp b/dll/win32/shell32/shell32.cpp index 0ae868780d1..ab3209d8481 100644 --- a/dll/win32/shell32/shell32.cpp +++ b/dll/win32/shell32/shell32.cpp @@ -209,8 +209,34 @@ HRESULT WINAPI IDefClFImpl::CreateInstance(IUnknown * pUnkOuter, REFIID riid, LP */ HRESULT WINAPI IDefClFImpl::LockServer(BOOL fLock) { - TRACE("%p->(0x%x), not implemented\n", this, fLock); - return E_NOTIMPL; + TRACE("%p->(0x%x)\n", this, fLock); + + if (fLock) + { + if (pcRefDll) + { + if (*pcRefDll == LONG_MAX) + ERR("pcRefDll is pinned, not incrementing\n"); + else + InterlockedIncrement(pcRefDll); + } + _pAtlModule->Lock(); + } + else + { + _pAtlModule->Unlock(); + if (pcRefDll) + { + if (*pcRefDll == LONG_MAX) + ERR("pcRefDll is pinned, not decrementing\n"); + else if (*pcRefDll > 0) + InterlockedDecrement(pcRefDll); + else + ERR("pcRefDll underflow\n"); + } + } + + return S_OK; } /************************************************************************** diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt b/modules/rostests/apitests/shell32/CMakeLists.txt index 596374dafa8..e2f793d26c2 100644 --- a/modules/rostests/apitests/shell32/CMakeLists.txt +++ b/modules/rostests/apitests/shell32/CMakeLists.txt @@ -17,6 +17,7 @@ list(APPEND SOURCE FindExecutable.cpp GetDisplayNameOf.cpp GUIDFromString.cpp + LockServer.cpp Int64ToString.cpp IShellFolderViewCB.cpp ItemIDList.cpp diff --git a/modules/rostests/apitests/shell32/LockServer.cpp b/modules/rostests/apitests/shell32/LockServer.cpp new file mode 100644 index 00000000000..a049117cadb --- /dev/null +++ b/modules/rostests/apitests/shell32/LockServer.cpp @@ -0,0 +1,66 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: MIT (https://spdx.org/licenses/MIT) + * PURPOSE: Test for LockServer + * COPYRIGHT: Copyright 2026 Alex Mendoza <05alex.mendozaa@gmail.com> + */ + +#include "shelltest.h" +#include + +static HRESULT CALLBACK CreateInstanceStub(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + return E_NOTIMPL; +} + +static void test_LockServer(void) +{ + IClassFactory *pcf = NULL; + LONG refDll = 0; + HRESULT hr; + + hr = SHCreateDefClassObject(IID_IClassFactory, + (LPVOID*)&pcf, + CreateInstanceStub, + (LPDWORD)&refDll, + IID_IUnknown); + ok(hr == S_OK, "SHCreateDefClassObject failed: %08lx\n", hr); + ok(pcf != NULL, "pcf is NULL\n"); + if (!pcf) + { + skip("pcf is NULL, skipping LockServer tests\n"); + return; + } + + ok(refDll == 1, "Expected refDll == 1 after init, got %ld\n", refDll); + + hr = pcf->LockServer(TRUE); + ok(hr == S_OK, "LockServer() failed: %08lx\n", hr); + ok(refDll == 2, "Expected refDll == 2 after lock, got %ld\n", refDll); + + hr = pcf->LockServer(FALSE); + ok(hr == S_OK, "LockServer() failed: %08lx\n", hr); + ok(refDll == 1, "Expected refDll == 1 after unlock, got %ld\n", refDll); + + hr = pcf->LockServer(FALSE); + ok(hr == S_OK, "LockServer() failed: %08lx\n", hr); + ok(refDll >= 0, "refDll went negative after unlock when not locked: %ld\n", refDll); + + hr = pcf->LockServer(TRUE); + ok(hr == S_OK, "LockServer() failed: %08lx\n", hr); + hr = pcf->LockServer(TRUE); + ok(hr == S_OK, "LockServer() failed: %08lx\n", hr); + hr = pcf->LockServer(FALSE); + ok(hr == S_OK, "LockServer() failed: %08lx\n", hr); + hr = pcf->LockServer(FALSE); + ok(hr == S_OK, "LockServer() failed: %08lx\n", hr); + + pcf->Release(); + ok(refDll == 0, "Expected refDll == 0 after Release, got %ld\n", refDll); +} + +START_TEST(LockServer) +{ + test_LockServer(); +} diff --git a/modules/rostests/apitests/shell32/testlist.c b/modules/rostests/apitests/shell32/testlist.c index 479dd474ca3..9bf2c1cf66d 100644 --- a/modules/rostests/apitests/shell32/testlist.c +++ b/modules/rostests/apitests/shell32/testlist.c @@ -21,6 +21,7 @@ extern void func_ILCreateFromPath(void); extern void func_ILIsEqual(void); extern void func_Int64ToString(void); extern void func_IShellFolderViewCB(void); +extern void func_LockServer(void); extern void func_menu(void); extern void func_OpenAs_RunDLL(void); extern void func_PathIsEqualOrSubFolder(void); @@ -80,6 +81,7 @@ const struct test winetest_testlist[] = { "ILIsEqual", func_ILIsEqual }, { "Int64ToString", func_Int64ToString }, { "IShellFolderViewCB", func_IShellFolderViewCB }, + { "LockServer", func_LockServer }, { "menu", func_menu }, //{ "OpenAs_RunDLL", func_OpenAs_RunDLL }, // Test hangs on Win 2003 { "PathIsEqualOrSubFolder", func_PathIsEqualOrSubFolder },