diff --git a/modules/rostests/apitests/win32u/CMakeLists.txt b/modules/rostests/apitests/win32u/CMakeLists.txt index 87494afc5a4..b0a311264c4 100644 --- a/modules/rostests/apitests/win32u/CMakeLists.txt +++ b/modules/rostests/apitests/win32u/CMakeLists.txt @@ -53,6 +53,7 @@ list(APPEND SOURCE # ntuser/NtUserCallHwndParamLock.c # ntuser/NtUserCallNoParam.c # ntuser/NtUserCallOneParam.c + ntuser/NtUserConvertMemHandle.c ntuser/NtUserCountClipboardFormats.c ntuser/NtUserCreateAcceleratorTable.c ntuser/NtUserCreateWindowEx.c diff --git a/modules/rostests/apitests/win32u/ntuser/NtUserConvertMemHandle.c b/modules/rostests/apitests/win32u/ntuser/NtUserConvertMemHandle.c new file mode 100644 index 00000000000..a553393b474 --- /dev/null +++ b/modules/rostests/apitests/win32u/ntuser/NtUserConvertMemHandle.c @@ -0,0 +1,132 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Test for NtUserConvertMemHandle + * COPYRIGHT: Copyright 2025 Max Korostil (mrmks04@yandex.ru) + */ + +#include "../win32nt.h" + +HGLOBAL createGlobalMemory(const CHAR* pString, DWORD stringLength) +{ + HGLOBAL hGlobalBuffer = NULL; + CHAR* pLockedBuffer = NULL; + + hGlobalBuffer = GlobalAlloc(GMEM_DDESHARE, stringLength); + if (hGlobalBuffer == NULL) + { + return hGlobalBuffer; + } + + pLockedBuffer = (CHAR*)GlobalLock(hGlobalBuffer); + if (pLockedBuffer) + { + memcpy(pLockedBuffer, pString, stringLength); + } + + GlobalUnlock(hGlobalBuffer); + + return hGlobalBuffer; +} + +HANDLE setClipboardData(UINT uFormat, HANDLE hGlobalMem) +{ + DWORD dwSize = 0; + PVOID pMem = NULL; + HANDLE hRet = NULL; + HANDLE hMem = NULL; + SETCLIPBDATA scd = {FALSE, FALSE}; + + // Get global memory + pMem = GlobalLock(hGlobalMem); + dwSize = GlobalSize(hGlobalMem); + + hMem = NtUserConvertMemHandle(pMem, dwSize); + GlobalUnlock(hGlobalMem); + if (hMem == NULL) + { + return hMem; + } + + scd.fGlobalHandle = TRUE; + hRet = NtUserSetClipboardData(uFormat, hMem, &scd); + + return hRet; +} + +HANDLE getClipboardData(UINT uFormat) +{ + HANDLE hData = NULL; + HANDLE hGlobal = NULL; + PVOID pData = NULL; + DWORD cbData = 0; + GETCLIPBDATA gcd; + + hData = NtUserGetClipboardData(uFormat, &gcd); + if (gcd.fGlobalHandle) + { + NtUserCreateLocalMemHandle(hData, NULL, 0, &cbData); + hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbData); + + if (hGlobal == NULL) + { + return hGlobal; + } + + pData = GlobalLock(hGlobal); + NtUserCreateLocalMemHandle(hData, pData, cbData, NULL); + GlobalUnlock(hGlobal); + } + + return hGlobal; +} + +START_TEST(NtUserConvertMemHandle) +{ + HANDLE hMem; + CONST CHAR testString[] = "Test string"; + HGLOBAL hGlobal = NULL; + + hMem = NtUserConvertMemHandle(UlongToPtr(0xDEADBEEF), 0xFFFF); + ok_hdl(hMem, NULL); + + // Alloc global memory + hGlobal = createGlobalMemory(testString, sizeof(testString)); + if (hGlobal == NULL) + { + skip("hGlobal is NULL\n"); + } + else + { + HANDLE hMem = NULL; + HANDLE hRet = NULL; + + OpenClipboard(NULL); + hRet = setClipboardData(CF_TEXT, hGlobal); + CloseClipboard(); + + if (hRet == NULL) + { + skip("Set clipboard data failed\n"); + goto cleanup; + } + + OpenClipboard(NULL); + hMem = getClipboardData(CF_TEXT); + CloseClipboard(); + + if (hMem) + { + PVOID pData = GlobalLock(hMem); + ok_long(memcmp(pData, testString, sizeof(testString)), 0); + GlobalUnlock(hMem); + } + else + { + skip("Get clipboard data failed\n"); + } + + cleanup: + GlobalFree(hGlobal); + } +} diff --git a/modules/rostests/apitests/win32u/testlist.c b/modules/rostests/apitests/win32u/testlist.c index 4f4c92cedb1..04cae0bb9be 100644 --- a/modules/rostests/apitests/win32u/testlist.c +++ b/modules/rostests/apitests/win32u/testlist.c @@ -48,6 +48,7 @@ extern void func_NtGdiTransformPoints(void); //extern void func_NtUserCallHwndParamLock(void); //extern void func_NtUserCallNoParam(void); //extern void func_NtUserCallOneParam(void); +extern void func_NtUserConvertMemHandle(void); extern void func_NtUserCountClipboardFormats(void); extern void func_NtUserCreateAcceleratorTable(void); extern void func_NtUserCreateWindowEx(void); @@ -121,6 +122,7 @@ const struct test winetest_testlist[] = //{ "NtUserCallHwndParamLock", func_NtUserCallHwndParamLock }, //{ "NtUserCallNoParam", func_NtUserCallNoParam }, //{ "NtUserCallOneParam", func_NtUserCallOneParam }, + { "NtUserConvertMemHandle", func_NtUserConvertMemHandle }, { "NtUserCountClipboardFormats", func_NtUserCountClipboardFormats }, { "NtUserCreateAcceleratorTable", func_NtUserCreateAcceleratorTable }, { "NtUserCreateWindowEx", func_NtUserCreateWindowEx }, diff --git a/win32ss/user/ntuser/clipboard.c b/win32ss/user/ntuser/clipboard.c index 72aaaa1aaf8..b92a31d09de 100644 --- a/win32ss/user/ntuser/clipboard.c +++ b/win32ss/user/ntuser/clipboard.c @@ -1190,6 +1190,7 @@ NtUserConvertMemHandle( { HANDLE hMem = NULL; PCLIPBOARDDATA pMemObj; + NTSTATUS Status = STATUS_SUCCESS; UserEnterExclusive(); @@ -1208,7 +1209,7 @@ NtUserConvertMemHandle( } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - pMemObj = NULL; + Status = _SEH2_GetExceptionCode(); } _SEH2_END; @@ -1216,7 +1217,7 @@ NtUserConvertMemHandle( UserDereferenceObject(pMemObj); /* If we failed to copy data, remove handle */ - if (!pMemObj) + if (!NT_SUCCESS(Status)) { UserDeleteObject(hMem, TYPE_CLIPDATA); hMem = NULL;