diff --git a/modules/rostests/apitests/user32/CMakeLists.txt b/modules/rostests/apitests/user32/CMakeLists.txt index ccfecb9a340..e49fad457b2 100644 --- a/modules/rostests/apitests/user32/CMakeLists.txt +++ b/modules/rostests/apitests/user32/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(makeimg) list(APPEND SOURCE AttachThreadInput.c @@ -30,6 +31,7 @@ list(APPEND SOURCE KbdLayout.c keybd_event.c LoadImage.c + LoadImageGCC.c LookupIconIdFromDirectoryEx.c MessageStateAnalyzer.c NextDlgItem.c diff --git a/modules/rostests/apitests/user32/LoadImageGCC.c b/modules/rostests/apitests/user32/LoadImageGCC.c new file mode 100644 index 00000000000..007991135b6 --- /dev/null +++ b/modules/rostests/apitests/user32/LoadImageGCC.c @@ -0,0 +1,262 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Test for LoadImageW using DLL compiled with MSVC + * COPYRIGHT: Copyright 2024 Doug Lyons + * + * NOTES: + * Works on ReactOS, but not on Windows 2003 Server SP2. + */ + +#include "precomp.h" +#include "resource.h" +#include +#include + +WCHAR szWindowClass[] = L"testclass"; + +BOOL FileExistsW(PCWSTR FileName) +{ + DWORD Attribute = GetFileAttributesW(FileName); + + return (Attribute != INVALID_FILE_ATTRIBUTES && + !(Attribute & FILE_ATTRIBUTE_DIRECTORY)); +} + +BOOL ResourceToFileW(INT i, PCWSTR FileName) +{ + FILE *fout; + HGLOBAL hData; + HRSRC hRes; + PVOID pResLock; + UINT iSize; + + if (FileExistsW(FileName)) + { + /* We should only be using %temp% paths, so deleting here should be OK */ + printf("Deleting '%S' that already exists.\n", FileName); + DeleteFileW(FileName); + } + + hRes = FindResourceW(NULL, MAKEINTRESOURCEW(i), MAKEINTRESOURCEW(RT_RCDATA)); + if (hRes == NULL) + { + skip("Could not locate resource (%d). Exiting now\n", i); + return FALSE; + } + + iSize = SizeofResource(NULL, hRes); + + hData = LoadResource(NULL, hRes); + if (hData == NULL) + { + skip("Could not load resource (%d). Exiting now\n", i); + return FALSE; + } + + // Lock the resource into global memory. + pResLock = LockResource(hData); + if (pResLock == NULL) + { + skip("Could not lock resource (%d). Exiting now\n", i); + return FALSE; + } + + fout = _wfopen(FileName, L"wb"); + fwrite(pResLock, iSize, 1, fout); + fclose(fout); + return TRUE; +} + +static struct +{ + PCWSTR FileName; + INT ResourceId; +} DataFiles[] = +{ + {L"%SystemRoot%\\bin\\image.dll", IDR_DLL_NORMAL}, +}; + +/* MessageBox statements are left commented out for debugging purposes */ +static LRESULT CALLBACK +WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HBITMAP hBmp; + HANDLE handle; + CHAR buffer[80]; + + switch (message) + { + case WM_CREATE: + { + handle = LoadLibraryExW(L"image.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); + sprintf(buffer, "%p", handle); +// MessageBoxA(NULL, buffer, "handle", 0); + hBmp = (HBITMAP)LoadImage(handle, MAKEINTRESOURCE(130), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + sprintf(buffer, "%p", hBmp); +// MessageBoxA(NULL, buffer, "Bmp", 0); + sprintf(buffer, "%ld", GetLastError()); +// MessageBoxA(NULL, buffer, "LastError", 0); + break; + } + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc, hdcMem; + BITMAP bitmap; + BITMAPINFO bmi; + hdc = BeginPaint(hWnd, &ps); + HGLOBAL hMem; + LPVOID lpBits; + CHAR img[8] = { 0 }; + UINT size; + + hdcMem = CreateCompatibleDC(hdc); + SelectObject(hdcMem, hBmp); + GetObject(hBmp, sizeof(BITMAP), &bitmap); + sprintf(buffer, "H = %ld, W = %ld", bitmap.bmHeight, bitmap.bmWidth); +// MessageBoxA(NULL, buffer, "test", 0); + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = bitmap.bmWidth; + bmi.bmiHeader.biHeight = bitmap.bmHeight; + bmi.bmiHeader.biPlanes = bitmap.bmPlanes; + bmi.bmiHeader.biBitCount = bitmap.bmBitsPixel; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + + size = ((bitmap.bmWidth * bmi.bmiHeader.biBitCount + 31) / 32) * 4 * bitmap.bmHeight; + sprintf(buffer, "size = %d", size); +// MessageBoxA(NULL, buffer, "size", 0); + + hMem = GlobalAlloc(GMEM_MOVEABLE, size); + lpBits = GlobalLock(hMem); + GetDIBits(hdc, hBmp, 0, bitmap.bmHeight, lpBits, &bmi, DIB_RGB_COLORS); + + /* Get bottom line of bitmap */ + memcpy(img, lpBits, 8); + sprintf(buffer, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + img[0] & 0xff, img[1] & 0xff, img[2] & 0xff, img[3] & 0xff, + img[4] & 0xff, img[5] & 0xff, img[6] & 0xff, img[7] & 0xff); +// MessageBoxA(NULL, buffer, "chars 1st Line", 0); + + /* Get one line above bottom line of bitmap */ + memcpy(img, (VOID *)((INT_PTR)lpBits + 4 * bitmap.bmWidth), 8); + sprintf(buffer, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + img[0] & 0xff, img[1] & 0xff, img[2] & 0xff, img[3] & 0xff, + img[4] & 0xff, img[5] & 0xff, img[6] & 0xff, img[7] & 0xff); +// MessageBoxA(NULL, buffer, "chars 2nd Line", 0); + + ok(img[0] == 0, "Byte 0 Bad\n"); + ok(img[1] == 0, "Byte 1 Bad\n"); + ok(img[2] == 0, "Byte 2 Bad\n"); + ok(img[3] == 0, "Byte 3 Bad\n"); + + GlobalUnlock(hMem); + GlobalFree(hMem); + + DeleteDC(hdcMem); + + EndPaint(hWnd, &ps); + break; + } + + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +static ATOM +MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEXW wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = NULL; + + return RegisterClassExW(&wcex); +} + + +static BOOL +InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hWnd = CreateWindowExW(0, + szWindowClass, + L"Bmp test", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 300, + 120, + NULL, + NULL, + hInstance, + NULL); + + if (!hWnd) + { + return FALSE; + } + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + return TRUE; +} + +START_TEST(LoadImageGCC) +{ + UINT i; + WCHAR PathBuffer[MAX_PATH]; + + /* Windows 2003 cannot run this test. Testman shows CRASH, so skip it. */ + if (!IsReactOS()) + return; + + /* Extract Data Files */ + for (i = 0; i < _countof(DataFiles); ++i) + { + ExpandEnvironmentStringsW(DataFiles[i].FileName, PathBuffer, _countof(PathBuffer)); + + if (!ResourceToFileW(DataFiles[i].ResourceId, PathBuffer)) + { + printf("ResourceToFile Failed. Exiting now\n"); + goto Cleanup; + } + } + + MyRegisterClass(NULL); + + if (!InitInstance(NULL, SW_NORMAL)) // SW_NORMAL is needed or test does not work + { + printf("InitInstance Failed. Exiting now\n"); + } + + /* We would normally have a message loop here, but we don't want to wait in this test case */ + +Cleanup: + for (i = 0; i < _countof(DataFiles); ++i) + { + ExpandEnvironmentStringsW(DataFiles[i].FileName, PathBuffer, _countof(PathBuffer)); + DeleteFileW(PathBuffer); + } +} diff --git a/modules/rostests/apitests/user32/makeimg/CMakeLists.txt b/modules/rostests/apitests/user32/makeimg/CMakeLists.txt new file mode 100644 index 00000000000..6799025bcb4 --- /dev/null +++ b/modules/rostests/apitests/user32/makeimg/CMakeLists.txt @@ -0,0 +1,14 @@ +PROJECT(MAKEIMG) + +add_executable(showimg showimg.c) + +set_module_type(showimg win32gui UNICODE) +add_importlibs(showimg gdi32 user32 shell32 msvcrt kernel32 ntdll) + +add_library(image MODULE image.rc) +set_module_type(image win32dll ENTRYPOINT 0 ) + + +add_rostests_file(TARGET showimg) +add_rostests_file(TARGET image) + diff --git a/modules/rostests/apitests/user32/makeimg/image.rc b/modules/rostests/apitests/user32/makeimg/image.rc new file mode 100644 index 00000000000..b683331dfb3 --- /dev/null +++ b/modules/rostests/apitests/user32/makeimg/image.rc @@ -0,0 +1,4 @@ +#define IDB_TEST 130 + +IDB_TEST BITMAP "test.bmp" + diff --git a/modules/rostests/apitests/user32/makeimg/readme.txt b/modules/rostests/apitests/user32/makeimg/readme.txt new file mode 100644 index 00000000000..9a4cb17bbab --- /dev/null +++ b/modules/rostests/apitests/user32/makeimg/readme.txt @@ -0,0 +1,14 @@ +For reference see https://jira.reactos.org/browse/CORE-17005. + +This should be compiled using MSVC to create the image.dll file for testing. +Also, it creates an interactive showimg.exe program that can be used to verify this file. +After the creation of the image.dll file using MSVC it can be used to create user32_apitest:LoadImageGCC. +Simply copy the MSVC created 'image.dll' into the 'modules\rostests\apitests\user32' subdirectory to use it. +This file already exists there so that this step is not necessary, but only presents another option. + +Unfortunately, this test will not work correctly using Windows 2003 Server SP2. +I have not looked into the details of why this is the case, but it works under ReactOS. +This is what is important for now in any case. + +Doug Lyons +April 16, 2024 diff --git a/modules/rostests/apitests/user32/makeimg/showimg.c b/modules/rostests/apitests/user32/makeimg/showimg.c new file mode 100644 index 00000000000..63ade474fc5 --- /dev/null +++ b/modules/rostests/apitests/user32/makeimg/showimg.c @@ -0,0 +1,154 @@ +// Released to the Public Domain by Doug Lyons on April 16th, 2024. + +#include +#include + +WCHAR szWindowClass[] = L"testclass"; + +static LRESULT CALLBACK +WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static HBITMAP hBmp; + HANDLE handle; + CHAR buffer[32]; + + switch (message) + { + case WM_CREATE: + { + handle = LoadLibraryExW(L"image.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); + sprintf(buffer, "%p", handle); + MessageBoxA(NULL, buffer, "handle", 0); + hBmp = (HBITMAP)LoadImage(handle, MAKEINTRESOURCE(130), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + sprintf(buffer, "%p", hBmp); + MessageBoxA(NULL, buffer, "Bmp", 0); + sprintf(buffer, "%ld", GetLastError()); + MessageBoxA(NULL, buffer, "LastError", 0); + break; + } + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc, hdcMem; + BITMAP bitmap; + BITMAPINFO bmi; + hdc = BeginPaint(hWnd, &ps); + HGLOBAL hMem; + LPVOID lpBits; + + hdcMem = CreateCompatibleDC(hdc); + SelectObject(hdcMem, hBmp); + GetObject(hBmp, sizeof(BITMAP), &bitmap); + + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = bitmap.bmWidth; + bmi.bmiHeader.biHeight = bitmap.bmHeight; + bmi.bmiHeader.biPlanes = bitmap.bmPlanes; + bmi.bmiHeader.biBitCount = bitmap.bmBitsPixel; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + + hMem = GlobalAlloc(GMEM_MOVEABLE, ((bitmap.bmWidth * + bmi.bmiHeader.biBitCount + 31) / 32) * 4 * bitmap.bmHeight); + lpBits = GlobalLock(hMem); + GetDIBits(hdc, hBmp, 0, bitmap.bmHeight, lpBits, &bmi, DIB_RGB_COLORS); + + // increasing the multiplier makes the image larger + StretchDIBits(hdc, 0, 0, bitmap.bmWidth * 3, bitmap.bmHeight * 3, 0, 0, + bitmap.bmWidth, bitmap.bmHeight,lpBits, &bmi, DIB_RGB_COLORS, SRCCOPY); + GlobalUnlock(hMem); + GlobalFree(hMem); + + DeleteDC(hdcMem); + + EndPaint(hWnd, &ps); + break; + } + + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + + +static ATOM +MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = NULL; + + return RegisterClassEx(&wcex); +} + + +static BOOL +InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hWnd = CreateWindowEx(0, + szWindowClass, + L"Bmp test", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 300, + 120, + NULL, + NULL, + hInstance, + NULL); + + if (!hWnd) + { + return FALSE; + } + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + return TRUE; +} + +int WINAPI +wWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + MSG msg; + + MyRegisterClass(hInstance); + + if (!InitInstance(hInstance, nCmdShow)) + { + return FALSE; + } + + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (int)msg.wParam; +} diff --git a/modules/rostests/apitests/user32/resource.h b/modules/rostests/apitests/user32/resource.h index 33972fde705..87412d3cdb5 100644 --- a/modules/rostests/apitests/user32/resource.h +++ b/modules/rostests/apitests/user32/resource.h @@ -4,3 +4,4 @@ #define IDR_ICONS_PNG 2000 #define IDR_ICONS_NORMAL 2001 #define IDR_EXE_NORMAL 2002 +#define IDR_DLL_NORMAL 2003 diff --git a/modules/rostests/apitests/user32/testlist.c b/modules/rostests/apitests/user32/testlist.c index 101ec0a3892..3e90ebfcfbd 100644 --- a/modules/rostests/apitests/user32/testlist.c +++ b/modules/rostests/apitests/user32/testlist.c @@ -32,6 +32,7 @@ extern void func_InitializeLpkHooks(void); extern void func_KbdLayout(void); extern void func_keybd_event(void); extern void func_LoadImage(void); +extern void func_LoadImageGCC(void); extern void func_LookupIconIdFromDirectoryEx(void); extern void func_MessageStateAnalyzer(void); extern void func_NextDlgItem(void); @@ -91,6 +92,7 @@ const struct test winetest_testlist[] = { "KbdLayout", func_KbdLayout }, { "keybd_event", func_keybd_event }, { "LoadImage", func_LoadImage }, + { "LoadImageGCC", func_LoadImageGCC }, { "LookupIconIdFromDirectoryEx", func_LookupIconIdFromDirectoryEx }, { "MessageStateAnalyzer", func_MessageStateAnalyzer }, { "NextDlgItem", func_NextDlgItem }, diff --git a/modules/rostests/apitests/user32/user32_apitest.rc b/modules/rostests/apitests/user32/user32_apitest.rc index 155390fc217..6279d19db16 100644 --- a/modules/rostests/apitests/user32/user32_apitest.rc +++ b/modules/rostests/apitests/user32/user32_apitest.rc @@ -11,6 +11,7 @@ TESTCURSOR CURSOR "test.cur" IDR_ICONS_PNG RCDATA "ROS.ico" IDR_ICONS_NORMAL RCDATA "sysicon.ico" IDR_EXE_NORMAL RCDATA "cpimg2e.exe" +IDR_DLL_NORMAL RCDATA "image.dll" TESTDIALOG DIALOG 0,0, 200,200 CLASS "TestDialogClass" diff --git a/modules/rostests/apitests/user32/image.dll b/modules/rostests/apitests/user32/image.dll new file mode 100644 index 0000000000000000000000000000000000000000..8dc8d9d2b3a0630573bf989f5e03092703e24d22 GIT binary patch literal 6656 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 literal 0 HcmV?d00001