From 53c104131693936c787644d5d2cd53264c43bae9 Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Sun, 26 Jul 2026 19:18:57 +0200 Subject: [PATCH 1/4] Example.exe in plain C --- Example/{CpuUsage.cpp => CpuUsage.c} | 4 +- Example/CpuUsage.h | 2 +- Example/Example.c | 357 ++++++++++++++++++++++ Example/Example.cpp | 255 ---------------- Example/Example.h | 14 +- Example/Example.ico | Bin 16594 -> 10682 bytes Example/Example.vcxproj | 22 +- Example/Example.vcxproj.filters | 8 +- TestConsoleLauncher/TestConsoleLauncher.c | 5 +- r77/Rootkit.c | 2 +- 10 files changed, 389 insertions(+), 280 deletions(-) rename Example/{CpuUsage.cpp => CpuUsage.c} (88%) create mode 100644 Example/Example.c delete mode 100644 Example/Example.cpp diff --git a/Example/CpuUsage.cpp b/Example/CpuUsage.c similarity index 88% rename from Example/CpuUsage.cpp rename to Example/CpuUsage.c index c8d3efa..a608288 100644 --- a/Example/CpuUsage.cpp +++ b/Example/CpuUsage.c @@ -14,7 +14,7 @@ VOID InitializeCpuUsage() GetSystemInfo(&systemInfo); CpuUsageThreadCount = systemInfo.dwNumberOfProcessors; - CpuUsageThreads = new HANDLE[CpuUsageThreadCount]; + CpuUsageThreads = NEW_ARRAY(HANDLE, CpuUsageThreadCount); for (DWORD i = 0; i < CpuUsageThreadCount; i++) { @@ -30,7 +30,7 @@ VOID UninitializeCpuUsage() CloseHandle(CpuUsageThreads[i]); } - delete[] CpuUsageThreads; + FREE(CpuUsageThreads); } static DWORD WINAPI CpuUsageThreadFunc(LPVOID parameter) { diff --git a/Example/CpuUsage.h b/Example/CpuUsage.h index a3b51d7..06a4b65 100644 --- a/Example/CpuUsage.h +++ b/Example/CpuUsage.h @@ -1,4 +1,4 @@ -#include +#include "r77mindef.h" #ifndef _CPUUSAGE_H #define _CPUUSAGE_H diff --git a/Example/Example.c b/Example/Example.c new file mode 100644 index 0000000..f3f92e4 --- /dev/null +++ b/Example/Example.c @@ -0,0 +1,357 @@ +#define COBJMACROS +#include "Example.h" +#include "resource.h" +#include "CpuUsage.h" +#include "r77def.h" +#include "r77win.h" +#include +#include +#include + +int main() +{ + WCHAR executablePath[MAX_PATH + 1]; + GetModuleFileNameW(NULL, executablePath, MAX_PATH); + + LPWSTR fileName = PathFindFileNameW(executablePath); + + WCHAR processId[100]; + Int32ToStrW(GetCurrentProcessId(), processId); + + StrCpyW(Title, fileName); + StrCatW(Title, L" (PID: "); + StrCatW(Title, processId); + StrCatW(Title, L")"); + + if (!StrCmpNIW(fileName, HIDE_PREFIX, HIDE_PREFIX_LENGTH)) + { + WindowWidth = 460; + WindowHeight = 200; + ShowWarningIcon = FALSE; + + StrCpyW(Text, L"This executable's filename starts with \""); + StrCatW(Text, HIDE_PREFIX); + StrCatW(Text, L"\"\n\n"); + StrCatW(Text, L" - A task manager that is injected with r77 will not display this process.\n"); + StrCatW(Text, L" - File Explorer (or any other file browser) will not display this file.\n"); + StrCatW(Text, L" - etc... (see documentation)"); + } + else + { + WindowWidth = 400; + WindowHeight = 150; + ShowWarningIcon = TRUE; + + StrCpyW(Text, L"Rename this executable's file to start with \""); + StrCatW(Text, HIDE_PREFIX); + StrCatW(Text, L"\".\n"); + StrCatW(Text, L"It will be hidden by r77."); + } + + HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (SUCCEEDED(result) || result == RPC_E_CHANGED_MODE) + { + TextFont = CreateFontW(16, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI"); + TitleFont = CreateFontW(26, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI"); + WhiteBrush = CreateSolidBrush(RGB(255, 255, 255)); + LightGrayBrush = CreateSolidBrush(RGB(240, 240, 240)); + LogoImage = GetImageResource(IDB_EXAMPLE32, "PNG"); + HelpImage = GetImageResource(IDB_HELP16, "PNG"); + WarningImage = GetImageResource(IDB_WARNING16, "PNG"); + + WNDCLASSW wc; + i_memset(&wc, 0, sizeof(wc)); + wc.hInstance = GetModuleHandleW(NULL); + wc.lpszClassName = L"R77EXAMPLE"; + wc.lpfnWndProc = WindowProc; + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + wc.hbrBackground = WhiteBrush; + + if (RegisterClassW(&wc)) + { + RECT rect; + SetRect(&rect, 0, 0, WindowWidth, WindowHeight); + + if (AdjustWindowRectEx(&rect, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, FALSE, WS_EX_DLGMODALFRAME)) + { + Window = CreateWindowExW(WS_EX_DLGMODALFRAME, wc.lpszClassName, L"r77 Rootkit Example File", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, wc.hInstance, NULL); + if (Window) + { + CpuUsageComboBox = CreateWindowW(WC_COMBOBOXW, NULL, WS_TABSTOP | WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, 15, WindowHeight - 35, 120, 200, Window, NULL, wc.hInstance, NULL); + SendMessageW(CpuUsageComboBox, WM_SETFONT, (WPARAM)TextFont, TRUE); + SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 0%"); + SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 25%"); + SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 50%"); + SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 75%"); + SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 100%"); + SendMessageW(CpuUsageComboBox, CB_SETCURSEL, 0, 0); + + HelpButton = CreateWindowW(WC_BUTTONW, L"", WS_TABSTOP | WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, 140, WindowHeight - 35, 23, 23, Window, NULL, wc.hInstance, NULL); + + CloseButton = CreateWindowW(WC_BUTTONW, L"Close", WS_TABSTOP | WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, WindowWidth - 90, WindowHeight - 35, 75, 23, Window, NULL, wc.hInstance, NULL); + SendMessageW(CloseButton, WM_SETFONT, (WPARAM)TextFont, TRUE); + + InitializeCpuUsage(); + + ShowWindow(Window, SW_SHOW); + UpdateWindow(Window); + + MSG msg; + BOOL messageResult; + + while ((messageResult = GetMessageW(&msg, NULL, 0, 0)) != 0) + { + if (messageResult == -1) + { + break; + } + + if (!IsDialogMessageW(Window, &msg)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + UninitializeCpuUsage(); + } + } + + UnregisterClassW(wc.lpszClassName, wc.hInstance); + } + + if (TextFont) DeleteObject(TextFont); + if (TitleFont) DeleteObject(TitleFont); + if (WhiteBrush) DeleteObject(WhiteBrush); + if (LightGrayBrush) DeleteObject(LightGrayBrush); + if (LogoImage) DeleteObject(LogoImage); + if (HelpImage) DeleteObject(HelpImage); + if (WarningImage) DeleteObject(WarningImage); + + CoUninitialize(); + } + + return 0; +} + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + SetBkMode(hdc, TRANSPARENT); + + DrawBitmapAlpha(hdc, LogoImage, 20, 20); + + HFONT oldFont = (HFONT)SelectObject(hdc, TitleFont); + SetTextColor(hdc, RGB(0, 102, 204)); + TextOutW(hdc, 60, 20, Title, lstrlenW(Title)); + + if (ShowWarningIcon) + { + DrawBitmapAlpha(hdc, WarningImage, 60, 60); + } + + RECT rect; + if (ShowWarningIcon) + { + SetRect(&rect, 85, 60, WindowWidth - 45, WindowHeight - 50); + } + else + { + SetRect(&rect, 60, 60, WindowWidth - 20, WindowHeight - 50); + } + + SelectObject(hdc, TextFont); + SetTextColor(hdc, RGB(0, 0, 0)); + DrawTextW(hdc, Text, -1, &rect, DT_LEFT | DT_TOP | DT_WORDBREAK); + + SetRect(&rect, 0, WindowHeight - 45, WindowWidth, WindowHeight); + FillRect(hdc, &rect, LightGrayBrush); + + SelectObject(hdc, oldFont); + EndPaint(hwnd, &ps); + return 0; + } + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam; + if (drawItem && drawItem->hwndItem == HelpButton) + { + BITMAP bitmap; + i_memset(&bitmap, 0, sizeof(bitmap)); + + if (GetObjectW(HelpImage, sizeof(bitmap), &bitmap)) + { + DrawBitmapAlpha(drawItem->hDC, HelpImage, drawItem->rcItem.left + (drawItem->rcItem.right - drawItem->rcItem.left - bitmap.bmWidth) / 2, drawItem->rcItem.top + (drawItem->rcItem.bottom - drawItem->rcItem.top - bitmap.bmHeight) / 2); + } + + return TRUE; + } + break; + } + case WM_COMMAND: + { + if ((HWND)lParam == CloseButton && HIWORD(wParam) == BN_CLICKED) + { + DestroyWindow(hwnd); + } + else if ((HWND)lParam == HelpButton && HIWORD(wParam) == BN_CLICKED) + { + MessageBoxW(hwnd, L"CPU usage is hidden by r77. To see the effect, increase CPU usage of this process.\r\n\r\nThis process is running with idle priority to not interrupt other tasks.", L"Help", MB_OK | MB_ICONINFORMATION); + } + else if ((HWND)lParam == CpuUsageComboBox && HIWORD(wParam) == CBN_SELCHANGE) + { + switch ((DWORD)SendMessageW(CpuUsageComboBox, CB_GETCURSEL, 0, 0)) + { + case 0: SetCpuUsage(0); break; + case 1: SetCpuUsage(25); break; + case 2: SetCpuUsage(50); break; + case 3: SetCpuUsage(75); break; + case 4: SetCpuUsage(100); break; + } + } + + return 0; + } + case WM_SETCURSOR: + { + if ((HWND)wParam == HelpButton) + { + SetCursor(LoadCursorW(NULL, IDC_HAND)); + return TRUE; + } + break; + } + case WM_DESTROY: + { + Window = NULL; + PostQuitMessage(0); + return 0; + } + } + + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +HBITMAP GetImageResource(DWORD resourceID, LPCSTR type) +{ + LPBYTE resourceData; + DWORD resourceSize; + + if (GetResource(resourceID, type, &resourceData, &resourceSize)) + { + return CreateImage(resourceData, resourceSize); + } + + return NULL; +} +HBITMAP CreateImage(LPCBYTE data, DWORD size) +{ + HBITMAP bitmap = NULL; + + IWICImagingFactory *factory; + HRESULT result = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (LPVOID*)&factory); + if (SUCCEEDED(result)) + { + IWICStream *stream; + result = IWICImagingFactory_CreateStream(factory, &stream); + if (SUCCEEDED(result)) + { + result = IWICStream_InitializeFromMemory(stream, (LPBYTE)data, size); + if (SUCCEEDED(result)) + { + IWICBitmapDecoder *decoder; + result = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder); + if (SUCCEEDED(result)) + { + IWICBitmapFrameDecode *frame; + result = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); + if (SUCCEEDED(result)) + { + IWICBitmapSource *convertedSource; + result = WICConvertBitmapSource(&GUID_WICPixelFormat32bppPBGRA, (IWICBitmapSource *)frame, &convertedSource); + if (SUCCEEDED(result)) + { + UINT width; + UINT height; + result = IWICBitmapSource_GetSize(convertedSource, &width, &height); + if (SUCCEEDED(result) && width > 0 && height > 0) + { + BITMAPINFO bitmapInfo; + i_memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = (LONG)width; + bitmapInfo.bmiHeader.biHeight = -(LONG)height; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + LPVOID pixels; + bitmap = CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, NULL, 0); + + if (bitmap && pixels) + { + result = IWICBitmapSource_CopyPixels(convertedSource, NULL, width * 4, width * 4 * height, (LPBYTE)pixels); + if (FAILED(result)) + { + DeleteObject(bitmap); + bitmap = NULL; + } + } + else if (bitmap) + { + DeleteObject(bitmap); + bitmap = NULL; + } + } + + IWICBitmapSource_Release(convertedSource); + } + + IWICBitmapFrameDecode_Release(frame); + } + + IWICBitmapDecoder_Release(decoder); + } + } + + IWICStream_Release(stream); + } + + IWICImagingFactory_Release(factory); + } + + return bitmap; +} +VOID DrawBitmapAlpha(HDC destination, HBITMAP image, DWORD x, DWORD y) +{ + if (destination && image) + { + BITMAP bitmap; + i_memset(&bitmap, 0, sizeof(bitmap)); + + if (GetObjectW(image, sizeof(bitmap), &bitmap)) + { + HDC source = CreateCompatibleDC(destination); + if (source) + { + HGDIOBJ oldImage = SelectObject(source, image); + + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 255; + blend.AlphaFormat = AC_SRC_ALPHA; + + AlphaBlend(destination, x, y, bitmap.bmWidth, bitmap.bmHeight, source, 0, 0, bitmap.bmWidth, bitmap.bmHeight, blend); + SelectObject(source, oldImage); + + DeleteDC(source); + } + } + } +} \ No newline at end of file diff --git a/Example/Example.cpp b/Example/Example.cpp deleted file mode 100644 index 352663f..0000000 --- a/Example/Example.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include "Example.h" -#include "resource.h" -#include "CpuUsage.h" -#include "r77def.h" -#include - -extern "C" -{ -#include "r77win.h" -} - -int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - WCHAR executablePath[MAX_PATH + 1]; - if (FAILED(GetModuleFileNameW(NULL, executablePath, MAX_PATH))) return 0; - - LPWSTR fileName = PathFindFileNameW(executablePath); - - WCHAR processId[100]; - Int32ToStrW(GetCurrentProcessId(), processId); - - StrCpyW(Title, fileName); - StrCatW(Title, L" (PID: "); - StrCatW(Title, processId); - StrCatW(Title, L")"); - - if (!StrCmpNIW(fileName, HIDE_PREFIX, HIDE_PREFIX_LENGTH)) - { - WindowWidth = 460; - WindowHeight = 200; - ShowWarningIcon = false; - - StrCpyW(Text, L"This executable's filename starts with \""); - StrCatW(Text, HIDE_PREFIX); - StrCatW(Text, L"\"\n\n"); - StrCatW(Text, L" - A task manager that is injected with r77 will not display this process.\n"); - StrCatW(Text, L" - File Explorer (or any other file browser) will not display this file.\n"); - StrCatW(Text, L" - etc... (see documentation)"); - } - else - { - WindowWidth = 400; - WindowHeight = 150; - ShowWarningIcon = true; - - StrCpyW(Text, L"Rename this executable's file to start with \""); - StrCatW(Text, HIDE_PREFIX); - StrCatW(Text, L"\".\n"); - StrCatW(Text, L"It will be hidden by r77."); - } - - - - ULONG_PTR gdiToken; - GdiplusStartupInput gdiInput; - GdiplusStartup(&gdiToken, &gdiInput, NULL); - - WNDCLASSW wc = { }; - wc.hInstance = hInstance; - wc.lpszClassName = L"R77EXAMPLE"; - wc.lpfnWndProc = WindowProc; - RegisterClassW(&wc); - - Window = CreateWindowExW( - WS_EX_DLGMODALFRAME, - wc.lpszClassName, - L"r77 Rootkit Example File", - WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, - CW_USEDEFAULT, - CW_USEDEFAULT, - WindowWidth, - WindowHeight, - NULL, - NULL, - hInstance, - NULL - ); - if (Window == NULL) return 0; - - TextFont = CreateFontW(16, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI"); - TitleFont = CreateFontW(26, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI"); - WhiteBrush = CreateSolidBrush(RGB(255, 255, 255)); - LightGrayBrush = CreateSolidBrush(RGB(240, 240, 240)); - LogoImage = GetImageResource(IDB_EXAMPLE32, "PNG"); - HelpImage = GetImageResource(IDB_HELP16, "PNG"); - WarningImage = GetImageResource(IDB_WARNING16, "PNG"); - - RECT windowRect = { 0, 0, WindowWidth, WindowHeight }; - AdjustWindowRect(&windowRect, GetWindowLongW(Window, GWL_STYLE), FALSE); - SetWindowPos(Window, NULL, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_NOMOVE); - SetClassLongPtrW(Window, GCLP_HBRBACKGROUND, (LONG_PTR)WhiteBrush); - ShowWindow(Window, nCmdShow); - - CpuUsageComboBox = CreateWindowW(WC_COMBOBOXW, NULL, WS_TABSTOP | WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, 15, WindowHeight - 35, 120, 23, Window, NULL, hInstance, NULL); - SendMessageW(CpuUsageComboBox, WM_SETFONT, (WPARAM)TextFont, TRUE); - SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 0%"); - SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 25%"); - SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 50%"); - SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 75%"); - SendMessageW(CpuUsageComboBox, CB_ADDSTRING, 0, (LPARAM)L"CPU Usage: 100%"); - SendMessageW(CpuUsageComboBox, CB_SETCURSEL, 0, 0); - - HelpButton = CreateWindowW(WC_STATICW, NULL, WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_NOTIFY | SS_CENTERIMAGE, 140, WindowHeight - 35, 23, 23, Window, (HMENU)1, hInstance, NULL); - SendMessageW(HelpButton, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)HelpImage); - - CloseButton = CreateWindowW(WC_BUTTONW, L"Close", WS_TABSTOP | WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, WindowWidth - 90, WindowHeight - 35, 75, 23, Window, NULL, hInstance, NULL); - SendMessageW(CloseButton, WM_SETFONT, (WPARAM)TextFont, TRUE); - - InitializeCpuUsage(); - - MSG msg; - while (GetMessageW(&msg, NULL, 0, 0)) - { - if (!IsDialogMessageW(Window, &msg)) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - - UninitializeCpuUsage(); - GdiplusShutdown(gdiToken); - return 0; -} -LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - SetBkMode(hdc, TRANSPARENT); - HDC hdcMem = CreateCompatibleDC(hdc); - BITMAP bitmap; - - // Window logo - HBITMAP oldBitmap = (HBITMAP)SelectObject(hdcMem, LogoImage); - GetObject(LogoImage, sizeof(bitmap), &bitmap); - BitBlt(hdc, 20, 20, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); - - // Title - HFONT oldFont = (HFONT)SelectObject(hdc, TitleFont); - SetTextColor(hdc, RGB(0, 102, 204)); - TextOutW(hdc, 60, 20, Title, lstrlenW(Title)); - - // Warning icon - if (ShowWarningIcon) - { - SelectObject(hdcMem, WarningImage); - GetObject(WarningImage, sizeof(bitmap), &bitmap); - BitBlt(hdc, 60, 60, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY); - } - - // Text - RECT rect; - - if (ShowWarningIcon) - { - rect = { 85, 60, WindowWidth - 45, WindowHeight - 50 }; - } - else - { - rect = { 60, 60, WindowWidth - 20, WindowHeight - 50 }; - } - - SelectObject(hdc, TextFont); - SetTextColor(hdc, RGB(0, 0, 0)); - DrawTextW(hdc, Text, -1, &rect, DT_LEFT | DT_TOP | DT_WORDBREAK); - - // Button row background - rect = { 0, WindowHeight - 45, WindowWidth, WindowHeight }; - FillRect(hdc, &rect, LightGrayBrush); - - SelectObject(hdc, oldFont); - SelectObject(hdcMem, oldBitmap); - DeleteDC(hdcMem); - EndPaint(hwnd, &ps); - } - break; - case WM_COMMAND: - if (lParam == (LPARAM)CloseButton) - { - DestroyWindow(hwnd); - } - else if (lParam == (LPARAM)HelpButton) - { - MessageBoxW(hwnd, L"CPU usage is hidden by r77. To see the effect, increase CPU usage of this process.\n\nThis process is running with idle priority to not interrupt other tasks.", L"Help", MB_OK | MB_ICONINFORMATION); - } - else if (lParam == (LPARAM)CpuUsageComboBox && HIWORD(wParam) == CBN_SELCHANGE) - { - switch ((int)SendMessageW(CpuUsageComboBox, CB_GETCURSEL, 0, 0)) - { - case 0: SetCpuUsage(0); break; - case 1: SetCpuUsage(25); break; - case 2: SetCpuUsage(50); break; - case 3: SetCpuUsage(75); break; - case 4: SetCpuUsage(100); break; - default: throw; - } - } - break; - case WM_SETCURSOR: - if ((HWND)wParam == HelpButton) - { - SetCursor(LoadCursorW(NULL, IDC_HAND)); - return TRUE; - } - else - { - SetCursor(LoadCursorW(NULL, IDC_ARROW)); - return TRUE; - } - case WM_DESTROY: - PostQuitMessage(0); - break; - default: - return DefWindowProcW(hwnd, msg, wParam, lParam); - } - - return 0; -} - -HBITMAP GetImageResource(DWORD resourceID, LPCSTR type) -{ - LPBYTE resourceData; - DWORD resourceSize; - - if (GetResource(resourceID, type, &resourceData, &resourceSize)) - { - return CreateImage(resourceData, resourceSize); - } - - return NULL; -} -HBITMAP CreateImage(LPCBYTE data, DWORD size) -{ - HBITMAP result = NULL; - - IStream *imageStream = SHCreateMemStream(data, size); - if (imageStream) - { - Bitmap *bitmap = new Bitmap(imageStream); - - if (bitmap->GetHBITMAP(Color::Transparent, &result) != Ok) - { - result = NULL; - } - - delete bitmap; - imageStream->Release(); - } - - return result; -} \ No newline at end of file diff --git a/Example/Example.h b/Example/Example.h index 80f6ad2..adbe0bd 100644 --- a/Example/Example.h +++ b/Example/Example.h @@ -1,12 +1,9 @@ +#define CUSTOM_ENTRY #include "r77mindef.h" -#include -#include -#include -using namespace Gdiplus; -int WindowWidth; -int WindowHeight; -bool ShowWarningIcon; +DWORD WindowWidth; +DWORD WindowHeight; +BOOL ShowWarningIcon; WCHAR Title[500]; WCHAR Text[1000]; @@ -25,4 +22,5 @@ HBITMAP WarningImage; LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); HBITMAP GetImageResource(DWORD resourceID, LPCSTR type); -HBITMAP CreateImage(LPCBYTE data, DWORD size); \ No newline at end of file +HBITMAP CreateImage(LPCBYTE data, DWORD size); +VOID DrawBitmapAlpha(HDC destination, HBITMAP image, DWORD x, DWORD y); \ No newline at end of file diff --git a/Example/Example.ico b/Example/Example.ico index 370332cf67ba21263de136d8e4b28e4f30c5f2a4..8e03a0c2646bd6052a79e3f98ff18cb8ca081876 100644 GIT binary patch delta 152 zcmccA$ha%mg@J*QfrUXp07NS=NHQ@nxG^v=C@4Vq-f29Rdxln&``5Ky`sk&sRq^3Whi3(_GeA}JsYF?2{tOP8c{gTNi{ z?>^tX|9t0<^FHr-&W>}=-fO*UH|vatpa38c3J4QKK=3!xfhbTxAX^X!L`U~eeu)MG z0Z5FO_n*8C0|a`52?EK;{F66gfj|PdAW(4dKe;SE2((9p>;QTF?XQFy1ma`_f!=DW zD?_lM*hmjmgIAox z&v2%(nJI}UFs)5UH+ns^tndc4g)#4I!ZVxBtsdPn);{`LUu)dS`cjcrj{e7FZFI#w zt8kb$`DfVyk5AXv^M|6jjD357(qAu^;2pP!u&P7<(ZfrLcK^est!#f()IUdE_|nK5 zfNv2R{V|K$2cK$pQWCkjq>-=CzPy;QH>@Mfj=41EK4$0j*HE=>8!Va?bl!6EUS zoU=?O^G$?{tss96#RiLdqC|;tgFD6sd-X)2T6JQ8&HX^ildq05+{W-XTqLBV#TK$MquG9ipvG>M>dkKtNQJB+nt&HnF*$VWv4THYTH`r4?S~-P_Zn z_4+lNq~BTpFqj%b6)OY=gRR%-u{>1hd|Fa4u1ML<+X7T3N?uSh>TeaPq}czgwb9kn zQ*3lyF3HWM**!cY3piejxWa2+C8yfsCiS2%?Y>lpk*#d_vUJfy{pu&fSZYYZ1Kao#bdifYtCJbF5 zVqPnlWNlSkEs=l3=c)^-To+s0y1^hC|9y%cCO{BR;k+6Niku$p7+y?cocnj8Glz0|Xa$tjTjr zA>!rBmsDhX9GzhVXI34}-4)S#oN(R5&Yktyx7>r#t~|0Qrx?7cUwWo!(6kt^}j zoj>%}Nglb|)f(1<~-t$rxsef-6~awb$3DIygG^)C!~(X&P1hDwH`s zJ|?E2aTy>&=X*>knusHsL892t^U~^z9I;ewZEaRY zMtKRz=?WwH`37go)#LTPzN4WGey{c3I4ueHweX!9alq$*>TSeqe~2k^iT7Scdv1+P zMYa8EW0fIgfIuKxZf@1doygg^TnUtk{82Hs+wtV)#_w37cOAcPW^!^Yo?4t$QZfe>4XyPl zU*L@wpyed7{CIu(iwT3Rrzd}on78Vm&D}TM>V)7klQv(+p^!EOg_bzM`FfP4R{t4m z*El)Y)4a^ga@Qa?u-6;g{n0$>D!kWcZ+(q|4U@Cd#wfFxr2?+1m4A49d(+_Lk4~EY zeeaU04MHNKb4eA8s|rx_oly;pz`YTu(K16dIxUDd}NcD|Kc~e5vvA*uYn0sOiQ1M;ng5PK?tS(`u-uo z@qP67Z?(1BrYeYuQjOQh-?=UnUm!Z?AoIlX6QCE~n10?n@~NWY9Vw6bZ+)1DM{OIE zAa**wf`Y=geY(2Z+HNXY5)D+e`a>sxuZjf4HPIv88WS{{D@ioEz6ke0l4@4C{h!4~ z*SuL`wvg4ipiSi=i>VLfG9+YVvCeLWN35)@`7trrd@X`TL8A#eLuOADXdbt|Ekqr$zoiwc#Ksvqu|dU zo}!9LOCO9B*5H4uY?qYP_y0#_@hbnLvN_;H;wg&0sH{{&RPQb=Oyp_maH8lr@Cp4o&s}(+mltz91Htm;(sTJDfm3+NwE#&%sd^u+?7xwOMsd=JE zn_muzxA@%XPSa!eT1`9XOY7HD_00B&Z>`YF=iuAG9+sJ)&Hm=5_b$hW7d_t0UxW$Wd+u_W~24|B@UMtl7`9_|r;+3}8??yO= zr|4fUf=I7&;yoELyF=6e@G;nS$5SQ7qHipilwQtRp*hstbBWaf4?)dqF&x^s!$oa@ zx8usRfeL*IwD_KUuP{bJJQv;jsC9L9iCLvKLbI9ZE{#PS7O6z8tv)gWBqStWzfuh_ zx!WvydU^z`dvV#3TiYB)Mby_TTKg6vN-qrV@_5zg>vlq^AbfLqn3viSBb z=CJ)CXrptTT!b{9LXdld1;r=iBoS>5>>{@wd1XY|W*DJ(?Kt*~rvV`Ky zeSeY6!F_nBCH-{EN2P&>g=^|R-1nG3taVuoRujE4c=4s+yn@Ki@kgBE;^M&}Aw6bh z=2{%f7BRb1balTk%P1{qCJj!XT4mgEL>UZ1>UXn;(L`1wE8bWAhPkMdYv!9i8&?AH zK+8{NU?M*|KB6T^UZh`iZm9O_bz17(L-C)8D-Ye5f36%iPd5d?O{(dIgBI(nuO5Dl zQpGXJQtDyL_Un!F>J|)I6s{`FryN~f9>5PBcvLIT*J62M$UqXWt9ot1R+*GzG7`x7 zhcTGbJ)OWG0AH5b}CPPI0$l6Vn3M;UZ82L%RlF`l9Ba# z)P#e`!enm|B2)(|>(Y-ajOxCU$$dzKhmZUPJ^Ffz-R7MeU-N`>)BAvR^kB|R*`|Y< zxm{8CI!H>Z|NE@C1i@@kr{nrcxAFKx)C+OTZQagbxou(zf?#E?LU9-J?8z4|OOUis zeSx}7Dv{`>Sw zI@`GM0n!Kt7^*A!irIZ7x7@)AD_gc&A<)G>Y`?my<&aO}QEFBi%r*f=8xqnwQtE7B z73`;=vNs`xHatn3KYXAiBn_MenmnIORascTf0SS^As9mnb3f=vo`=q8Igo&*dpzI?Fi?yj0r7D(V&SXUwJ9Xu0Cc@3L2&?U} zf;otg*%2$MV=J^k|A%+ zVMn;LCL}B3zJ~tAyfqW4PtWlsjzADvDN}gUH3JM|bcI?X{KI3B^{HCB#7^rUk>|uO zsU^H#IxV;5ka8I-TrT?1E(YE1PZp^Vi5<3_ex)>G4gGMwJ5^}j>L*ImFOzqx~%{p=h^Cz5{*3d88e@px|m3puo1lu|4C52%nQvdP<}63&l>(m z+~qYs4{xN65O~#3;IP!vbkY4~L(W-~aZ>f^+$_F>B&*S%H#;%yNNeMF)Pc40=X7)? zH(O7nz_yIqA$^s>J_={W==h0Y=f)3ZTD@k=lvJ96$g<*BMo{30lRNl*&mJDN*sCl@ z9L+K|2M*070*j6o@5K(|9>#%8bln|P*m|7sS1bpT1Wl8l7>Q3=sYlb0g^<-Jr8ww_ z-(d2aFzRohTmlP8WZ68NB|I9xzy&IZG^~+;XfQR}CpFOhxmr&+Tksr>Fm9S3#QkSh zn3D^Oosq!9mcumuPSEMu&cq1kG@DL|2v(&@W90?<7ww45e4(-*4bJn~nKq#MHnG(x zi!0}nSj6b%GN8d>Q0XPcDdx2;Gn^?n;eu#lf#Dr$p-rL+g8N-2#puI;BhP8m>7;yR zG+0}=pKzVsXh|O}u#j==&@Np@)be|wi9e2lALu8M&U@2*0kf1Q_3h5mCi2YWc^iqW1=$!?M!Ze~i$FzWo%gv2 z=^@6yxv$HCaRjWsNR^p1x)eMFt#!X0HzX*;)Wn%Yua}KmTQ>io;X&cZ>d3H1%T)1T z_m%_(8C|{8oVKYUlR#i-B}|12%I5(*82B#x?XRXL%v{+vM$qw^^D3Fer<2}hskv#k zvqV@Bb5V5cFIOTX}6Hl8(nDL6Q&g8_Sm+&p^N+jAkjFjcx%P8rYNq+@{}-DwY7hJubU< zS!KBU3!-R}PPMZHb<$WH8>5d!ZzZ1zTSF&$e_S!HwpZ-V#T-PTUB{9yGA2k6-tr4K zi~65!KQ>(NOYngjJ>7|3TkHEniXmV%SNXYl?#tM%sg!GD{f2aF|P@vho&rqYP{T^}4t z2O^85SHH8Q0jV#BHER{T&d{nS5j2v2f+{1+txC8@qJB0HkRQ$NB>;~z1zsng@=I_l zWtd0hDud-G^?4bnG%ff#Gx+Ty)k&4C)B}W^7MrJKUf5@(cp1B6Nvfr{->;qtK}dptc zkFv&ovK!4U7~wLKCr@vh5NTqJ)j^md+3hoy`qh&Ep`L9+IUMAI90k{`BA4*21-axu z9=6@8OW>AVrcV*2hogNSo?}s>D$&~R#Nokh9#>2)n@b@8>WXxEy>}-yw_Z%#Tsmb7 zzQe^bd`($V{WgJGT&VUZ+~-hVD4IC0ORGZ+0rPw0r#`gzfMgS!sAi#&8^y?ljzTsZ z1?yA}2_a^=^q^76%Q1Xu^vqIiFlSv!GqcCp_79_;(1SJPNl%oyz~0SX)d%VWetoBU z9ZW2v*Fp@yO*aw!3)jVF!PY+~-wS$sfZP4X$#wuJ?um+tiOEKRCcAEE6Yyig=%SoP zE_X`v2Jyrh(n3E)E%o_RUr^doxu&)7{|PSqlAr6b%f+ zRJEdyA48`r&GrO91@7$gp6}Dr1{>1)a-VwZ&9DQc{boM-<7jtjTqX=vw9$bV)mxQi zyc$sU@JJTENZ!2Top7Nj0ouSq-Ki%}+z=2${~pdGn|^KvHZo&b>FW(5qhr1u#@vYf z_3$tn`tO*HC)F0%IA->=&vXI;P*igUb9fTrgI74U6=R4HUk|ZM{LXz+E>A;e9RplV z6%_#NyzouSmMFcbh`f0Py}XW{N8{J=Y7}knxNnNOJtbnAliX$BB9-!sS5@l;6zQ_I zDvtK&>OK9$m@TeA<^jnk$J0D(X6WPMvV;M`TNkwzWfj@ z9fSppzL0ul09IZA_K?QASJL~<8Oo(o4K%z!a>{!sa5^k(P#<()#H&ZSILO{!v9^v$ zmR96wU>v|6?$d^=UV)`HH@J$`xP=rL9U~(O@53d@tLGUF z=V5$9NN}7Hx&4v9eq1)OJlVz)q_>)VKk+>tF+rgd?};rU7)3oyqojEEn12CqsQISX zET0Syx~DbtWF5`{b9h-w20w3wUEPPmj_yzxgL#AbH^flV*90P_o@*!y$hw%I+yH2c zWQv2|zvrOJyS81I@Si@pc73NZ1d_tJXX*~6$@{9;^`U#CCeLq|tu%`F`cPoFK^8%2 z3H^1tnaED()5qbI8~X#Ff}<1&-hXeaW9uPaOWGR{R2{P*2_4Gbsv`0@#4gTNNfP>= z6dbjmr{{j3xp4q1_W)C!(G{G6%zhaLf3B8Z*Xy)Br}x=>oGD*t#_fo|mq0%{pSm!d z7V7;_9I8S&`w1lrglBcfzzvMB^_%q(e9pYj5R6^$5%}6;ckjNumu{dJ$o2V6xaWP$ zLhDs>-`QbR^~B{3l!sdY$l|l!G7VWMu>SySX5I7@JkR+Yl)Y8^k8S*4yV&#c-x;&o hJyvZUN=yYE#{km)(xkB9QvCPe`R`G55-uC{zW}Fs78?Kn diff --git a/Example/Example.vcxproj b/Example/Example.vcxproj index f286018..a508e44 100644 --- a/Example/Example.vcxproj +++ b/Example/Example.vcxproj @@ -47,16 +47,21 @@ Level3 - true + false WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp14 MultiThreadedDebug + CompileAsC + false + Default Windows true - ntdll.lib;shlwapi.lib;pathcch.lib;windowscodecs.lib + ntdll.lib;kernel32.lib;advapi32.lib;user32.lib;gdi32.lib;comctl32.lib;shlwapi.lib;ole32.lib;windowscodecs.lib;msimg32.lib;pathcch.lib + true + EntryPoint app.manifest %(AdditionalManifestFiles) @@ -80,12 +85,15 @@ copy /Y "$(TargetPath)" "$(SolutionDir)$Build/$77-Example.exe" Size MultiThreaded false + CompileAsC Windows false - ntdll.lib;shlwapi.lib;pathcch.lib;windowscodecs.lib + ntdll.lib;kernel32.lib;advapi32.lib;user32.lib;gdi32.lib;comctl32.lib;shlwapi.lib;ole32.lib;windowscodecs.lib;msimg32.lib;pathcch.lib false + true + EntryPoint app.manifest %(AdditionalManifestFiles) @@ -96,10 +104,6 @@ mkdir "$(SolutionDir)$Build" copy /Y "$(TargetPath)" "$(SolutionDir)$Build/$77-Example.exe" - - - - @@ -114,6 +118,10 @@ copy /Y "$(TargetPath)" "$(SolutionDir)$Build/$77-Example.exe" + + + + diff --git a/Example/Example.vcxproj.filters b/Example/Example.vcxproj.filters index b3724c3..b432581 100644 --- a/Example/Example.vcxproj.filters +++ b/Example/Example.vcxproj.filters @@ -1,9 +1,5 @@  - - - - @@ -29,4 +25,8 @@ {b159945d-1e18-467a-a043-231fed0759ac} + + + + \ No newline at end of file diff --git a/TestConsoleLauncher/TestConsoleLauncher.c b/TestConsoleLauncher/TestConsoleLauncher.c index 4ed0d4c..9e62433 100644 --- a/TestConsoleLauncher/TestConsoleLauncher.c +++ b/TestConsoleLauncher/TestConsoleLauncher.c @@ -8,11 +8,12 @@ int main() // The launcher simply decides which version to launch based on the OS bitness. WCHAR applicationDirectory[MAX_PATH + 1]; + GetModuleFileNameW(NULL, applicationDirectory, MAX_PATH); + WCHAR targetPath[MAX_PATH + 1]; LPCWSTR targetFileName = Is64BitOperatingSystem() ? L"TestConsole\\x64\\TestConsole.exe" : L"TestConsole\\x86\\TestConsole.exe"; - if (FAILED(GetModuleFileNameW(NULL, applicationDirectory, MAX_PATH)) || - !PathRemoveFileSpecW(applicationDirectory) || + if (!PathRemoveFileSpecW(applicationDirectory) || !PathCombineW(targetPath, applicationDirectory, targetFileName)) { MessageBoxW(NULL, L"Error", L"Test Console", MB_OK | MB_ICONHAND); diff --git a/r77/Rootkit.c b/r77/Rootkit.c index fd0a1f9..92ffd7d 100644 --- a/r77/Rootkit.c +++ b/r77/Rootkit.c @@ -11,7 +11,7 @@ BOOL InitializeRootkit() { // If the process starts with $77, do not load r77. WCHAR executablePath[MAX_PATH + 1]; - if (FAILED(GetModuleFileNameW(NULL, executablePath, MAX_PATH))) return FALSE; + GetModuleFileNameW(NULL, executablePath, MAX_PATH); if (HasPrefix(PathFindFileNameW(executablePath))) return FALSE; // Write the r77 header. From 727e106a32c27e164a491c8ee066da1c5d44cfce Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Mon, 27 Jul 2026 23:31:13 +0200 Subject: [PATCH 2/4] TestConsoleLauncher splash screen --- Example/Example.c | 100 ++++---- Example/Example.h | 1 - TestConsole/TestConsole.csproj | 2 +- .../Windows/AboutDialog/AboutDialog.xaml | 2 +- .../Windows/MainWindow/MainWindow.xaml.cs | 1 + .../Windows/MainWindow/MainWindowViewModel.cs | 22 ++ .../Resources/SplashScreen.png | Bin 0 -> 22407 bytes TestConsoleLauncher/TestConsoleLauncher.c | 239 +++++++++++++++++- TestConsoleLauncher/TestConsoleLauncher.h | 11 + TestConsoleLauncher/TestConsoleLauncher.rc | Bin 3278 -> 3638 bytes .../TestConsoleLauncher.vcxproj | 6 +- TestConsoleLauncher/resource.h | 3 +- 12 files changed, 316 insertions(+), 71 deletions(-) create mode 100644 TestConsoleLauncher/Resources/SplashScreen.png create mode 100644 TestConsoleLauncher/TestConsoleLauncher.h diff --git a/Example/Example.c b/Example/Example.c index f3f92e4..2b818cd 100644 --- a/Example/Example.c +++ b/Example/Example.c @@ -244,88 +244,84 @@ HBITMAP GetImageResource(DWORD resourceID, LPCSTR type) if (GetResource(resourceID, type, &resourceData, &resourceSize)) { - return CreateImage(resourceData, resourceSize); - } + HBITMAP bitmap = NULL; - return NULL; -} -HBITMAP CreateImage(LPCBYTE data, DWORD size) -{ - HBITMAP bitmap = NULL; - - IWICImagingFactory *factory; - HRESULT result = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (LPVOID*)&factory); - if (SUCCEEDED(result)) - { - IWICStream *stream; - result = IWICImagingFactory_CreateStream(factory, &stream); + IWICImagingFactory *factory; + HRESULT result = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (LPVOID*)&factory); if (SUCCEEDED(result)) { - result = IWICStream_InitializeFromMemory(stream, (LPBYTE)data, size); + IWICStream *stream; + result = IWICImagingFactory_CreateStream(factory, &stream); if (SUCCEEDED(result)) { - IWICBitmapDecoder *decoder; - result = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder); + result = IWICStream_InitializeFromMemory(stream, resourceData, resourceSize); if (SUCCEEDED(result)) { - IWICBitmapFrameDecode *frame; - result = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); + IWICBitmapDecoder *decoder; + result = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder); if (SUCCEEDED(result)) { - IWICBitmapSource *convertedSource; - result = WICConvertBitmapSource(&GUID_WICPixelFormat32bppPBGRA, (IWICBitmapSource *)frame, &convertedSource); + IWICBitmapFrameDecode *frame; + result = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); if (SUCCEEDED(result)) { - UINT width; - UINT height; - result = IWICBitmapSource_GetSize(convertedSource, &width, &height); - if (SUCCEEDED(result) && width > 0 && height > 0) + IWICBitmapSource *convertedSource; + result = WICConvertBitmapSource(&GUID_WICPixelFormat32bppPBGRA, (IWICBitmapSource *)frame, &convertedSource); + if (SUCCEEDED(result)) { - BITMAPINFO bitmapInfo; - i_memset(&bitmapInfo, 0, sizeof(bitmapInfo)); - bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bitmapInfo.bmiHeader.biWidth = (LONG)width; - bitmapInfo.bmiHeader.biHeight = -(LONG)height; - bitmapInfo.bmiHeader.biPlanes = 1; - bitmapInfo.bmiHeader.biBitCount = 32; - bitmapInfo.bmiHeader.biCompression = BI_RGB; - - LPVOID pixels; - bitmap = CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, NULL, 0); - - if (bitmap && pixels) + UINT width; + UINT height; + result = IWICBitmapSource_GetSize(convertedSource, &width, &height); + if (SUCCEEDED(result) && width > 0 && height > 0) { - result = IWICBitmapSource_CopyPixels(convertedSource, NULL, width * 4, width * 4 * height, (LPBYTE)pixels); - if (FAILED(result)) + BITMAPINFO bitmapInfo; + i_memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = (LONG)width; + bitmapInfo.bmiHeader.biHeight = -(LONG)height; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + LPVOID pixels; + bitmap = CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, NULL, 0); + + if (bitmap && pixels) + { + result = IWICBitmapSource_CopyPixels(convertedSource, NULL, width * 4, width * 4 * height, (LPBYTE)pixels); + if (FAILED(result)) + { + DeleteObject(bitmap); + bitmap = NULL; + } + } + else if (bitmap) { DeleteObject(bitmap); bitmap = NULL; } } - else if (bitmap) - { - DeleteObject(bitmap); - bitmap = NULL; - } + + IWICBitmapSource_Release(convertedSource); } - IWICBitmapSource_Release(convertedSource); + IWICBitmapFrameDecode_Release(frame); } - IWICBitmapFrameDecode_Release(frame); + IWICBitmapDecoder_Release(decoder); } - - IWICBitmapDecoder_Release(decoder); } + + IWICStream_Release(stream); } - IWICStream_Release(stream); + IWICImagingFactory_Release(factory); } - IWICImagingFactory_Release(factory); + return bitmap; } - return bitmap; + return NULL; } VOID DrawBitmapAlpha(HDC destination, HBITMAP image, DWORD x, DWORD y) { diff --git a/Example/Example.h b/Example/Example.h index adbe0bd..472d3ed 100644 --- a/Example/Example.h +++ b/Example/Example.h @@ -22,5 +22,4 @@ HBITMAP WarningImage; LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); HBITMAP GetImageResource(DWORD resourceID, LPCSTR type); -HBITMAP CreateImage(LPCBYTE data, DWORD size); VOID DrawBitmapAlpha(HDC destination, HBITMAP image, DWORD x, DWORD y); \ No newline at end of file diff --git a/TestConsole/TestConsole.csproj b/TestConsole/TestConsole.csproj index fe2d3d8..65e11ac 100644 --- a/TestConsole/TestConsole.csproj +++ b/TestConsole/TestConsole.csproj @@ -22,7 +22,7 @@ r77 Test Console bytecode77 bytecode77 - © bytecode77, 2025. + © bytecode77, 2026. diff --git a/TestConsole/Windows/AboutDialog/AboutDialog.xaml b/TestConsole/Windows/AboutDialog/AboutDialog.xaml index 845b857..e29e91d 100644 --- a/TestConsole/Windows/AboutDialog/AboutDialog.xaml +++ b/TestConsole/Windows/AboutDialog/AboutDialog.xaml @@ -45,7 +45,7 @@ bytecode77/r77-rootkit - + \ No newline at end of file diff --git a/TestConsole/Windows/MainWindow/MainWindow.xaml.cs b/TestConsole/Windows/MainWindow/MainWindow.xaml.cs index 8240016..5702379 100644 --- a/TestConsole/Windows/MainWindow/MainWindow.xaml.cs +++ b/TestConsole/Windows/MainWindow/MainWindow.xaml.cs @@ -18,6 +18,7 @@ private void MainWindow_Loaded(object sender, RoutedEventArgs e) ProcessesTabPage.Focus(); ViewModel.WriteInitialLogEntries(); + ViewModel.TerminateLauncher(); } public void OpenControlPipeTabPage() diff --git a/TestConsole/Windows/MainWindow/MainWindowViewModel.cs b/TestConsole/Windows/MainWindow/MainWindowViewModel.cs index 85a7b9b..fb3e76c 100644 --- a/TestConsole/Windows/MainWindow/MainWindowViewModel.cs +++ b/TestConsole/Windows/MainWindow/MainWindowViewModel.cs @@ -1,4 +1,5 @@ using BytecodeApi; +using BytecodeApi.Extensions; using BytecodeApi.IO; using BytecodeApi.Rest; using BytecodeApi.Wpf; @@ -119,4 +120,25 @@ public void WriteInitialLogEntries() ); } } + public async void TerminateLauncher() + { + // The TestConsole launcher created this process and must be terminated. + + await Task.Run(async () => + { + await Task.Delay(250); + + using Process process = Process.GetCurrentProcess(); + using Process? parentProcess = process.GetParentProcess(); + + if (parentProcess?.ProcessName.Equals("TestConsole", StringComparison.OrdinalIgnoreCase) == true) + { + parentProcess.Kill(); + } + else + { + // TestConsole.exe was not started by the launcher, possibly by explorer. + } + }); + } } \ No newline at end of file diff --git a/TestConsoleLauncher/Resources/SplashScreen.png b/TestConsoleLauncher/Resources/SplashScreen.png new file mode 100644 index 0000000000000000000000000000000000000000..f92f35db51b0380a246f41a7cd12797cbdf02c45 GIT binary patch literal 22407 zcmeIacT`i`zBU}Ug{^EsM2b`eK@kCw-Yp0!A}Z2L1O$|7qzWO}KzdY^&_Pg;-iri+ zg(4zEq!S<#N{|3Cv;YaoHy7@G&$;Kj=e_6s=Z^P|aWY0mR#w*Rzczo*GZT6FlHu-M zLc3rv*zWV^^smBT+ek3j)&sxq0C(cHbOeBpEk0KbPs55kMSg%U+gwi>pMt^4(40(% z?cn>)+vlu&U@)!^(0dEtkqh_0&HcV-EqzVBU3>!^?l{9PJKXZ}mA`cM+5r`LMR~;& zyju)?!9%sqmgim0pFaxw9emji6WX#Jwgp^W0B_+xuR(WUN49L;y#E`xR^0L%j0b#L zgZHh++cxiefNSWr;J*bnz4dRO|JW)R6%6)-1GWu3d;Emb@hzFZ>V?|ep82b;1aJ+# zegifCw)x~$4Rvt!XDP+w$Dv;zhAN2M`Pxl{!OWG;>z}$7Xg@a+ochA7LGP!60Q$k3 zBS}#YnwmL}-j{h1_2AKK4d0oGm!HI)2hT-C-bhMHwr=(LvL|Za;f^K2<}%a6mt_(A znvEn5J|Kl{nUui%{LOxcLK~CyWTTS)@sBTmd~_5XrS`iwCX%szsFe!(Y=bM6+g+!? zY+_Dn_DO;K#<%Xp0`nH7X!GV7i_uSXsDrROE29NxM81V&Opo{wYp0{&;z9+|dZxpp z`GJyks7ZWdGl}3a>51%WZmu2XN}C8K1daixI=>u<@3ua zprsnu&%WHqI5m79zR}wlvOW%H&6FN2!*gi5I77uU9n6^+PKZ}S^sMsB^pTb5)+zZT!LNge>|1`l_}rfQ1%m=X|CxJ8z3W>2&W$1(w zG;`J!)BGVncRa0z_!+(%s>Qkz6yz^}-<7l`3k&7v9pXouVGRZ&q{8-Z#&8C`w$l&!I`@iDvl z<6h}Y@qu^9kH-gStxX4W#rKMGP4Dsa_u}>Rzr~C78B5UmaC6BMS2JB6HJ|Me*10Q5%4Gs7$0?W>Ar*C1em)7De9@~I-1m`|-QL*__be!wt4&T}D#}~cA169L z_G|fhP*_K-hCS8N!4k75w&a%#PfJvQ7UYJtpYUym4yv^M^Ac}!zvUDfmd!Y;-N%}r zUJgs|%J(Y>^z3q{^(EIh;_ZW58fRIkJlr>_{964HFJ*p zgzVt)C~H!1~(a^_h0)~Gw_+Oourj**i;lx?NIYHwOb)b z!iQdc<{+PK_UvAmtR)fP5mAJk=5js-Ob>%Tx1T7ap-f;cQ(c>$W5s2E@bV}wy~-Xp z$`F2{;QiD=veiY;J9fkS!sNq6$If^>W|$ssUFYbD0|u*fWc@u~KiQ~i{rzj=Crou- z61pQggg&TM=RcxG+{eRXlu#J+qQKmcosIsarZPY_wC`QzL3r1*tP2A@5wm?oXDYqA zHPai%*AlICwfdM#X^D4fPPCQen(-nGG0Lz}OUYi8ZLYoEYgM+Y5S{Ip($_V12HWz@ zBHx<1)Kko{5+SLJTr!X>Opc!$6Fl$w6Jgji5$RNJwD#jnRwywYaU0!9i*Lu-e)E5a zN+b0gG<;#phK5#UsK4TK=1jS_9m+@>d;2abF-Qls2q^OkO^s?RrVt+2` zgswGuYQFZHPc7H!aSm$*t7WO;8TjRX)Q-};EjCAHLjf17(@U0^1R#lzDd+jydY zxZa*&px+cVX*6Dop2hU`7Zt=sM3{*5J7tHc-Do6ysIq{king*Z=6_OaooyA1V%IX6 z&rnA8Z$1YQ1U95+5PQAkIBwC}6NCj)SZ<)I99z?PA)Lb`?qWoNu z><rjooDg$5*nez6^JBG!i7wpzWQ~kolDbrQtVqg;{i&DcwHuHY z9J8U_v0Wc0wwOp?k{L7{TXoaQdGH}b#&*|H@l*j&;Pr%h6k%5t^sKqUyp1isfPw>2 z%2(#($J!#k56ubN5K`7>Mb@j%jNeyd@2Sy27+11Zv1Jz2hOBOfw5;CN(KvSc;`l0M z9ZPz`^H{&~GyE+L71~cMKl!TIr}?bDcH_^aRa&TR;&xef$RghH$Fs9*UdB1MZ5Pu6 zJ>s`GlyT2Cc&GYxGRQMp)89WzN|bl`*qk}&p-HA>$nE4b*}on(?f2Dzho{V=ZIKqA zVI1W@H!A+%Eu1W`h-?~ETzvY2wp#c&i0yjEQ-pl}UL_%GGX4=;qa$9eaC*-s-yM;jH3^U&Ug>PhONX1_;7s4q+dJ!9Cp z@19MLZ{ux!zRfn^VhUdfH~aGWjDbDja`5FD>5rxL85dLcLN`@k_^#BSrOker++5I? zhegwRIZdx~50scf*2=?|tJ+!CKCY87Yjst21zPjLMgA8Ti{!Yzx^(7!j>`sy(CVhS zptIUtQsQcxGdynK_LnQl4J)4{>%8~)0*0&sk`)pyV=1h$S}iuCDKldn%ro8LN6^a_O)42BWj1+o#=i&6dxqob&{u1P7 ze6emn~>hCTII8rZ{hS4A)FC&r;nF&{P}yssrHmgWN*P01fkNSX8^dnR_Kir zpA|HnM;!w~jcL44#04ht7<}0cmuj^}x5#EL9USx@TjhLj$;RnaSQ9_$?UQA*SU62; zg)5{SF8$HFTWv+Qp?>&mb(~6#{n%4CFARbrrwM$4d4E_=ze9iMlzFqB+G}Y}l7xhH zji;z5p-N74x$kI}C$_q)&NzPb+C$`<)`N%*JnFfEx1YF<%VljPc4Xkv7{igSvl5f$ zKO~bL66B??uT7tgFLRrWUMoY4XzEFAA<|Udo{?fha#_w1bjFz<++_h z{Ej}8-k~R($0r=R!EUl>Z{$-FPfG9Y)TKVFCFMubK0SOfc;qb;#ksz;ar0uDs=_?h z)y;pt_BoesrOB{=JAQF8_DdowH*om{MnW}Jskm;vW7^vA_MnKFuDU{;c2+R7a1~^^ ze3eW>Dyf-I+C+r+AzDkqMg)oqTun{YCclfNISoc()CeUnaVmFiUQAbasW81vxk?BD z!P9ld6>ZU~YM&OB7oM0nDdnXKcvSW}_Ynv_nO?}r90j8sk7j#M7%+5ZO5+ghhJY8xRxYbfM68Z- zw=`eU+Av~0si|9RT+FsyIBn+dahO~45a)1|sDG0osU0pNVkp|DD9`HbcVsTJ0S7T!&oYe4?r>yc6j@@l`PBTbCjwvcqIj3|tAv+RI+tKSF;PY|!k< zPIa>ryk$YWRT-~V_|95g&z^Rz2hK(rEK#wD#JaZ(u*E&On4ovqmX(Sy&NHjoBGAY5 zA~DF)?h#Va0xeB>nAYOlsz{wW>QnF0R~8u|Dx+&o6m|FM*NBstSp2E&go;75&c09_ zC4kn@UfiK31$H7GjjE4pTvV{{T0xC;5Zg$Jvf)9G^$!)aCEQe?3m zUGA293?5ydf9pZ*h+buIVW?|J<=|W6KKn&`WBq~%^CGr}$#O%$Xtb(URis4*Z&TMD zPw!JAgzy7gFxbuWGuV6jKAfcaG?wKo7H=;cc6<9`hP|MyMZ@01T-ut%p6kZ^O}+IN zyif=xmNCcU8E{LOLbMWB=m?gvuDZpS#zoy%M5vAny~dX0H@4fyK;Fo(WRC`&5|K+d z5VyXk3AngfOI^K%d^tVC;S^b7j8r^4rYh7@z$jNP_Dy79NE@YWH9^4XM~Ov~un{o= z+!`}cXc{6GMK?Fv3H27Z>G9}QZZi}M@u>KH4A|LwQ_j&3Y6FOYY6+ud$8_r{Wr)80 z#OSk))*|lteN8hAcwDv?cN90(?;>-9g(3C2!eja3*<$2WKP!?iXocie0xPdjm6pxH|Z*APiLH(wnOQ*W(Q&c^(Z0HY3iy0f%OS;paZW8=+ znO;yHBlE1=lH=}^i>_tiQ|*q>rc^6I&RT^JYVb{lwAHVx0qs+p8|y;{A~pxMZ5sl5 z;K@B`rD3qWn@a&Z`J0?{1cSnhpM>_*u&*AKiNAhNt}xh+(5oe_8+$>;VXuV*n(WqN zjlI;G7M$^|9cs3GYQ)=S$KWeS+}rbZi=Vcakz%FRPC(Ck_{Hub?W(?UXqdM`Jjw<| z8(&4U>y-NfG>^w=OgF4{EN71=z?tgli5r)3!SR7N1}oLs^Y~WJ#g^6-DlXj{N=w}< za%q21YY_8DcH8a7+PjWSlyh$4-RZMs^`8Cem5VkAiUzf*&2AnY%%aZ}@qcPyj1p*% zT~Yfn!vO|N+Mtc&96^DM^(YfQjMVEZ&SRtcOF|V;3m?PvHWNS|dP00nlZGEAYbXl@ zn^5b$?;2L`k2{7GR8!UZ^eb>Y9Dj*jQo9yjuz3vI<2}al!Lx1WstO8Y=blo%~BKx8}@ z-P*!koFCDkH=x0#UTPsS$Zq|$J5BiD-29)H`iFUtyRBrWGuXa(wvMFuE zDO4y!W3|1kwKHv@!^R^wjU^?9n!c|-7Y#>$M5~`5iqJ;&NaBrerG_##UJNXjb7oW0 z0$Pea*-}Jk0`Kv^x^l`Eb;uTlm1oTNOX-$V@>f3<%U+P*zy`#G{_qXdUc1`=to_@} z*6g`U#sZg@hZjp%$1>r~iD;Gu@^*jc+LW{p@Lnw}4&;#_anuba)myqLCYY^YUTn!k zjR&(M0&vW=KfGA(UNFg`AeFUm6jG82HL*toeou^u2=r|ESmxjIv1=vfY1fo6nH&J6$KLtRFG`lU z4M)^ISdV)otDb3uwk-S3ny%=6{;b^y&phZ==j~vtRdc4z`SVtEE6XluBB0`IAFi&> zUN#xG+*cP7VYxUnv!mo@9S}nG=_k58JYB^hk5`-8;4w;u8^?phX{td$b!Q}&Lg8u@hulFaCDQEbiF$C(~-LVm4te_5#;N_)8p zK7K|gm>f`Xeq5S`>m2v0qRg*d%`tmCvH<)hu*4C-o~=E-y*5`@=`|v~E*^Yg_)cib zxA5d6uMkOFEk;BSi-sbR*Qpy9W^D5DPg|RZEZ|YpIM&tFt1Hc`E6q;X>{gCu9K-J} zTg2Z`T%3%eJf>AWCC1u>B8(xWL@c$Me5U4fS<`d!a2aYN7;NgY0w?ZkjicF0iaWS8-Btt)c>IxSwT#((nl)WNS+> zJ5Y_a{xxGfEI*gjYrztu;ux1^32X1vGu=z31D4)Rm)f+h5}df3Nr1sRLP$zS== z-4z`M zO)6FEalhPdkC2YUro+7{_@_Vq>i9st`zqwfZ+2Q=+_Rap?nwFvulztAs_WdzUqA2s z9l$j(*nus7Rgq7)$LYRf=|_6WrgJvF(K3A20E(?(CwKjyi(V$@=kek#(-h{88;sTm z{K`98)vd=Oci!7pH#>3=9<|>`U?<5=<~WTZ_^eJVZZH& zoE&JZCx82|+q!Qc*Y|Txyd%;z0hi=SL?MXkmF>k+A=R!aHicu|8Pmc7u|mn7CTS~y z%zk`s!qWLkS3R&F;vu8heb0heg79D`yVN`DXh~Ju-0pO2^G_d?y>G0XQyB;hZlY$a z3&$o-J#Gy!NPq50yi2XGoeIAt6(Z#J+1Rz!OVmG7i<%~op-YRX4I+)uavAAg0tl}d z(&#pnSCrFl1Ln!dvT%aJys*h7ZB?(vTJO}AY>l-kehSnF&@rLb4GQ1jbAmpNSqjsgdo1`Ua5_RfhiwkChK9@-C zJ0Os%a;UGqT7JiFVd4Ja<8t7W@O_UL)WbA-Cn3wJ4k|U&eyJU^B{>!ZiQ6Ch52|qe zD0kPkQ$AfRMF|M3QJ;sG9LbwB%vLcBP1jY^obS?wg9-3I9ugc72^vf2>1<@KJe%`$ zsNupskGbd0)w=B~kT;d(&pZv~Ki-7RH5c?XFWoKC?_HRQh*%wI4jIQ+*hg`CAyu(n zH08cr49@CA@_bulE6833c%$U!1D7@k>?v2Sn1y)mHx<+|N%7BaVIlp!HPst^ImLN- z0_mpw;`1YZ@!4(C8_d+{y3pJR>zs!M`b*Q*CbOe2?fU%3G@P%fzJmL26i8o;R0vra z2wdy!&nAwIkZ6bD5k8Hf6c>65_g1})NF1WmBK*ciR84e=(hoAZiFXlmqxEtYCAb^9%QK zhJ*F7($~pIH@Ej0t_}Oj9B$a^H;JN)<75q&j_w>wPYv`a>b5jtbftPkxg#u9e?~Nv z4~>95I+*hPHN%UJwmwtur9xy`mB(;vNn0zd4?e<9^li7AOIG3rIY_3hcEeJ~8*BTt zUdpa9RY(?NFz^r^c;~(xRG+G-vT95YW342|S#m~RJNFoiLN;}pscdy>i&khwu!GJH z-^DY~CTK546ZDNg!PBjAnf4klCd>)9e4${duRr(%HHhmkEb4qv2hFvAJtXr|_YXqy zJQzxhqb(#4;e`c+Ka>vaaoi1Nk6+#@t=I9)SHBHU?i&aDp`~#5O5_h1)lx{15B1Bw zH}{|-{Kk75oSb*lnp!JB6~}RHPUQq`_5z`zR8E5QYMeV(V-eHR_K*u5hplN}31&^! zw60-@V$eK;UlJbO4jUI$_V74=-4Y33Uzy(*0g)UU{DaDp32q#dZAW zQ|@LU)=|JT?T@x7ik@dwqk%$H-`M5R-w+U)!9pPTcNpj&v#*j*w_11c-+;6wKf$8) zrJa8)REXHH_O{UbjGPV4&3DMB2C31FK(9z;Pj+swiUyBVM?|z{AP;g5@#9L};>ihE z_EXpL47D0!9VE}%tD%^dhwOk``f}M*yK*iCYctmRLj#Wl`4SF0eq2@%QmMQlp22F; z3+)Gy+R7vlwJg)tSi@WUe1{wC+HSr@?ooAReVZNj=EM|^&fXnfA=WslTFcESjw~_T zz450jPYc%gt`#8OTb+?mjk%6x+|M01q3i6&`VG83bf~ZcvX0akZ5c=zY<>9C-9hhI%}QC4N) zgeqmc%@xxp3v-u`5^x{r@f|Xjv2DC9vn>)DFgcHG{(PIejZJQxCH4HhhLj>o_TtY{ySx>xlC9fdbbrceMqBiD9xWPAd57^q{nX8cL z+i!vs;+XFS#?W`!fFZZqb45G?au)%37I~RM=?tD~dL{smgY@Qn!*OHZj-i=nGTC~J zu?WirQu|pQVORILn(rSQur7K6CJrHUv3`TfW>ChC4qQ>p>vnjoj9QxARfU*iHj6`b z&#t)i+xuG|vtzkk!G|X?zLY<^m7cQeOO$ubaW^?t5g%Zkn$Ne23;AToh+al??CvJb zL1Lx6!GQYdjhcGrk$iJ3^>&#<@{EeBSgJ8XF6Iscuf!FV zKiO+lbeTQhfq&rk6CJ9RdYy4kmfnk<8Tew8#O9R?)}aLy0KWr71+)v z*4gI9o30`z|R;{GTd;ekS`QnP&~2jwmbcz$|Q?XI9D2kFjy zeL(tI{(JoIdwQ&A&zYL0MCIi{*o|@x_|)2E3RMcir4vx-cU?;rgi?#IV|WlSf`OeR zX)_T+C^O!UAgAdZga3BmKCR!l6Qe5HG@|)ZTSB6*$Ohy6K<)%PNg$hkkU?(m>5f}j zox4e|$-B!O5YjHG7DaEYv{60VE1O!qSxO2mhU?294y|(U2O$0IaI_k$+yZ2M22^Ku zky0g#BQGW%KPY`M@yRCYep3I@fnpixR>Co>y+#Sgcv?VbmCuBRklrG99?&>7%zyOJ zZ3}papKZu;?}yDe)J-aa@LTgi+xy4Ccy1P>ZZ|Kd4DYy3DYyK{zuFmqGu``vk8q6; zS1gr&TkW;z9F5R5?`^ucTBZ_c@2Mrmn2RS85^hDJi7R!MAMq{rdlgFTlN9>%x^pdf%3X5V-FXc?-gaW3AhWY-@abyP1MC+Gc%jSRtBc*8dB{w7?}yO zH#0M9es_Os1*$n@sK#47+Yl{3)E-w*+*(pzUVa6A#o5^z6vR!Gd0*PWB~sfl8hrHV zQK98T)x&dy8a$@@htq}jC!yl`g@wb@I;ln3xDul1vX70A8G%}ql_hahR< z*hsBvpsO`acV(*u#R}{rVvvn;4I`q1?Fx+|6|VTWc?)%){?lfGB;HlcyT$(Lg&uwO5(fa-U!^I8{r{3P) zt_m_k5+QVy9q^#2WR+^{qv$u&Gpk~6ZeD%miRI;C@0p&w)87pO*CsLJPYuN)rHm4q zoX|RbuN;N}7H@#Nmb++xQoW>A1&2~aNWaz04tsgr_x3fr9;19h9$Jq`Bdlhe=N-of zFja}$O3zjwiIANhtZ-eT5{csG$=A-LTa35FM&m*ls&@yh|9)<51cqP4)6vY?*iCaYdxbVTNiKFJV z`#81&d8p#DQV{F3zjCFl4d*wPB5Gu1Wpy!4Qw1)4n5}vA5hkqv+L(&k?eFgrHGEu_ zesmuW-p$`AA8mMV5>5}}apdFUlM3PN_ncNvUWeqaE!dc*XmRbDKB&fDWUV#R648*A z<(R#(uV41)(X9OZqhK+4m0UZ&%-f)RZ5eY*4SCh{u}{W2$FxHi@LL9+Gbx3cKZRs_ zqTv};I@C8dcGSqH!oB9hhuK4NEFHd4HO^(yMwuTUTP|wY-C^uQm{bTQh}c;$_x8%F zmIZh$b>J$PztIWAl^JO9xKTeJA|{?18suI|BaMr*1DPAtP_%PUp!Nd?>4Wm)sHmt~T8pp~7{nDT ztNlP<21}QizHfCy)}LQ=h}q%l zuu#5ehlbo9dvA#CIboLrdH9Z;y@Xsy3L$EQeW2BBeRKTd@Rh&_L#cno`qrSUGVz$8OgYRe`2u{BesrtG7)VL@e|KYyMk)Oh!~)VXi; ztfX5O0#h>K)BAJmW5tsj-{0Mr@(gPfy|NVWAjg!Me5)~%T`Hs#N#3n2JWU9j`GrHGJZZ)T=J1zFb0XViLm_Xu7ZGB93#Dq)ZBsI zwf)FI)`8-mFJBfG7EVN4&@i20oB|0kS7*SSJjY-R!Gfm2FO$C{@j^@c_-T@oYYVA4 zIy-%MdN57$lp@j`YkeCYyyU&5vlohsJuyG+8G4uEQaVkS|F}xf3EPK$E4| z1!a#TX;F)y)VLRZrEoRv1CXh44 zRFbQU_$UXrm`Lv>7$Hk}<*wi43kw6Zn9jnaXy=qzV^_AJA$7DtZ7}z>Y&~Y5eAv@F z#>f+Tk&MTu>xK1? zFxM6-NNxqO*xu2e9%(b}U9~}HV3lCDAu+|tcD$QnEf!Ye@w*XiQkbR&`l#@W7ccz6 z?>`m3(*LA!3$SSEHXSE_S%%(f%QFa12oHamAjD+f<`AGwAnY5 z&(Zd*@S12V3Uk2=f%8n!eo6s$vf_&0c3|V%S%zp)Jn*^M;HTZJcW))3c=*Yd0{V ziUIS($1G=wjg42%dpuoRB)hVA0=<2)of8t;Yimb>boph8$2*4CPNo<*n4hvA)3)Ee zCVWb0t!o-AJ~MbdXM)|A7D$TZ5k}GDrH!M2uW_l$fo2gn(9s+3423o`z8x~+h^zj2 zp4hy7RJG9aFRPn{+zPfR_n32&c7SDsh8Nx@!0kW<+5=3DU-qp_kXzI6nYvMRy5V?Q zaiFp-?RnJscxg|}dswU~lPRc+tmXD!_60M4BRh2g?$X}go*g23IIy!({;+X!<%sqa z7{irnhqCaY(STiadW*34v7|mzBE#bM;vs?99vNBLXdowQ6#6SB)fX(lpzl=rjFA3ID~QX}6fRx>m*w#<0ZE7iSMAD9Fkd(B0#W z+d~axQQRq70bXqk2im@+6+dR$b&9Z>mu*|{ZCdEc1hIRuB-=48>Cl`SlK%*cJMlwA zRd|eVff3E;&FyrvWONI_0_>|QtLJi_!4LYmk6f~IvnhO8Ep+ls)r{)*56N3X>c|uX zm6EiJ*cW3*C!<}1 ztY#wjUoQ|09ciIv2GJlVY z5qqU9hf1jaub6n5s9x2`FYG(u> zTy3h|*bA(OC#O4J_fi~cs!5po=XoO@& z;d#`8S7yOP#xf=gkuu%;$PrqLOD0W2DhlLwzoBfW+*(?7FxXuW4b^l%@o6$%+bE*- z+4PpR%g;GYlMR&L?AVi{ZaD1nu(nZ$#X4#Qb~DPco_tLk-=io-IoVS+Hs#@98)K8- zwV9E&F`PNzWhfo7^=iIsgiqXmk-NT0yJ)mMdF!9~>%SoBLMXRa8tXA_NRpy_-*#C7V`mcof|6t+D|D-Pq$ejS9l&*y2I`4gFL*O0Ub6Nw} zb%LN`zQks#eLv480wD9hbh!WS_J2pP_q=hmE!vWoCy;R*l>=H`w<@5-@Kc*1cHvYLlG6&#Vy^< zh8{L@bB)!;-UzlyT$_eF{rnE-*FNgf_i_$xHhKS=`6YtKJC*hND}zg4dE@k?3j_>O z_;ND&hd{&4dAZ0FUWtKrm4vm8lBBRu&VJe1l3J5dD@nZk+lGPLBVFX!&(#1Ql?+G? za}o|2eN$+ES$&lBqj-&R=VKG4T&Ajd1K=-nR1}C8E6$FyxgmyZaqCwaKtvfGtCwhI$3FR|t8 zwao}v>q)v!aBq-&^@mU8sExQ|`N9Ei|Cg=QC!F>CDSJ28VA6idW z>nJse-}#JQe6OSg*!1pQOb=3(Hm)mrW&f3(El!y5{O#2*A$h+qBf99e%*A#Qumswy z)!9PbTi-mTOpS!Wp8a4~3Gu0v=^4tM>6Z-^C_@qd+h2lb1`9pG+7dGo>Kx2^KVMg7Bt%3&b0ih5GR%JWQ7T$=o_Pz3jh`^E8PC56FHbrjWyGS# zKAPYGhyZE9&%>kQyE#f5_HJS~y??`Qgr)5T=KQ@x1BRCcqL0A{I={9q#`yGx3+Bf> zr`M)Bh3@(n1_y`ud#T@>`-_oNY6-OUooacNfIBR6ZSxxpc4$+FVfX$SsrFB&nz>0g z|6{sa2adKm{G1GNY?WU^IE~S6|M}+l#n)fH^?FYj!47?OrgE)a{qir{o4J=zUWL~&dj$b{DpeH`vB`eHEsoxW0K^MJ!W4j-LO5b;#(eMz z;qz5BA=YSn+vIky>L z_x9g7t{a+K>~VEF3P#4mgFv$FX(=-3$#w{VcI90dsF8i8(q3p2qF9<$VMVln(<Z;zS_|9ys0#B|Q0gGS@#>4DY za<{j!AbU>I%`6KY0D;61tk;X-9VdPI{>F4`E#mzQvCv@2Ux%vP7eQi(PHJ1b>hfbo z4NyGyPM6d5@R3%>o#rJ#+6TN2Z2Cr^tN+PI|1AJ6g@hJTYzyP%|Jae2Z%Q)k)xW0S z|Ae0RPa6D-asTg#``;1wKb6Y=%|fEA#3>;E1>-nU=U3*|n~&UoZ!Q9IDw#=1YTowe z1?ejU@79Ohx`N&f%jW0xVATqn0g+2iD4S&^Xklk3%B}tLD!R$Q zP*zIQ3h4Y$8%%9b^B=uSR-a0A%JL*suNA{Q3^zSW$K``D1ORP6x($!1AV(qBSBRisPpz4%w2)aM5$47R-8I*?&jCmmT&=-=`NW!_|8J=)p z?*SLJJH(^~A_+qNV<;;0SLyScM=17x%?-wh8Cf(wRe*XO2b|!uP0t3gU2B(zl(LM- zIu+}{XIEqZ<|yF9O#?EK;CdCM+#j?jRMI}`ml4hA+c~+m7q&A-&f(!=Rb+b*v@t}{{dYITDd83Cl&vJ5r+@vUcw{wOLzhJxStO{+71N5*tjSF(yWtrH>ApL zwC#1+JRxX&X^+Le4|ag4x2j~ zA^eM@ZL4vkClT7v{8$XMY}` zzW_>16QDy>5ae+7V|8nk=5U!pfUOTAaudBEEh{amN<1J>1pwohoU#=_ECNK5EI{u9 z)GedaIj0-IrL=MKKG5AYI~Dh>99%KN-t~%DZh#N-2%A3yaI>2^diR(WZ6gh!zSS83 zWp+lJ*wg&hSLTF4LmkTnN->0zzd$VwQ;~ZND~e4`2BZi z+}7p%!cCjR3?9Vy`y2*foF8+MpfU4GU;KngsRBQ=f_BPfUTrYw#EG|aIVKrmfROSRU#X`z z{D>Hj8jx=Q#s{7c_5@{ZPViM_Wo7l}1jLs>+Zq37+k1t^R=A<98`~JE(1d=Rc

-|vv``&rXkuwV>2;^D;a4!enS3-(S| z4CtDA2<0b}ONMZ>e5>{xrJg-2qaMF3-Z}k$A!qrw{m}pB$n&2bMfyh%`~Nz6{I5l- z|6Zzpb~5h&ZtMMb8hu4^g|ha|+-x)R4>Zc=z%spV>NDLqQ{!I`{gu@tw8mDQvhv+d zK@Rtw{~M6v1}W@i0}Mb05Fmx`aZMcL&6)BN5*OA%Hojd=&3eodX8m9X2eh}S6akFS zNI&lqygbNKV$|Iy2B92tE&KjsqoMWCB_~CYBVNEpK&g8uYi`w;zuj0MwFu-aff1Gk z{8;(T$nujdV$HcK-1EhY?ksqtr2Fn>7v1%KLG8eE)gd6!ZZxzd5FWoBp?0yp_{Nbt zWl&y!27Hmfq|Qow1_jaIWRPm@CXB*->&vbKs(zov-FHtrp809sPp>ECl{AM$p~pa` zJrbl;E$*a!*f&6;V*KW0*=f9)Z{5HK1Og~tov(TEhqHXW%qYM)0>OcND*{M(~c(ZHYlnfGr`I|JbZQ09J?@%`smuJ^v@&^U*e z+HD-ay&{wk^~i({Ppbo9r3nHq2>lz}+TdTu9?61)`DV(xQ-(v?#&~a&&c+h6_6Mfs z1|jTVo0%CWlCw>Rr}50tWlal(5tVlK*xmnkzFG(r-x-DQ-Ssnjl~X9O!rA z;Q>g-^DpT_VC9~@-yi05WE(OJR#ZLyrry;$Mp*CVD}Lei^q|j&D+rsg3ymbOFak>s z15{Zz!e*3|Q+uqb5#t+}f?(J)6!1W!M zlW+w2^lZ=-1jy;T>BQw`q>F=WzpjM$s3|@HI4U&Xfhtfvmri8>a;^a0S33fiM%0{Fj3OfWEFE01NQu zrZ2Q1HP)B4zR@pU$AW{y^AR7p4sKIIwmn@(lM}S_oMSg0?_+4LsC6yC68F+Fz@tbB9+?4vPbL1C)-3H?AYgK6r#pwK(_B0xdAfzPX+8**#E2Kz`y2}cr6#d zeL&`ICN!Y`wQS{HicsJl(13UTaue4%_ZfUBx_irE_{8`e(#PPJySK?azPIxiYB{hA z?EYe)#4*^Y9MIeAc$v{@sp_mcN$ zFs0v+kmjD{N8h>#*Cq8Lczgq$*ON3S zkO5yra~D%e4OQc`e$MmUk-=9xTUyEN~qgwntvVas0U_9i6(AMnx_v zm>JnelHs +#include int main() { - // TestConsole is written in WPF .net 9.0 and deployed as a self-contained application, instead of AnyCPU. + // TestConsole is written in WPF .net 10.0 and deployed as a self-contained application. // The launcher simply decides which version to launch based on the OS bitness. + // This executable shows a splash screen and starts the actual TestConsole.exe, + // which will then terminate this process to hide the splash screen. + WCHAR applicationDirectory[MAX_PATH + 1]; GetModuleFileNameW(NULL, applicationDirectory, MAX_PATH); - WCHAR targetPath[MAX_PATH + 1]; + WCHAR testConsolePath[MAX_PATH + 1]; LPCWSTR targetFileName = Is64BitOperatingSystem() ? L"TestConsole\\x64\\TestConsole.exe" : L"TestConsole\\x86\\TestConsole.exe"; if (!PathRemoveFileSpecW(applicationDirectory) || - !PathCombineW(targetPath, applicationDirectory, targetFileName)) + !PathCombineW(testConsolePath, applicationDirectory, targetFileName)) { MessageBoxW(NULL, L"Error", L"Test Console", MB_OK | MB_ICONHAND); return 0; } - if (!PathFileExistsW(targetPath)) + if (!PathFileExistsW(testConsolePath)) { WCHAR message[1000]; StrCpyW(message, L"File '"); @@ -31,20 +37,227 @@ int main() return 0; } + SetProcessDPIAware(); + + HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (SUCCEEDED(result) || result == RPC_E_CHANGED_MODE) + { + WNDCLASSEXW wc; + i_memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.hInstance = GetModuleHandleW(NULL); + wc.lpfnWndProc = WindowProc; + wc.lpszClassName = L"TESTCONSOLE"; + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + + if (RegisterClassExW(&wc)) + { + Window = CreateWindowExW(WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE, wc.lpszClassName, NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, wc.hInstance, NULL); + if (Window) + { + SplashScreenImage = GetImageResource(IDB_SPLASHSCREEN, "PNG"); + + SetWindowSplashScreen(Window, SplashScreenImage); + ShowWindow(Window, SW_SHOWNOACTIVATE); + + StartTestConsole(testConsolePath); + + MSG message; + while (GetMessageW(&message, NULL, 0, 0) > 0) + { + TranslateMessage(&message); + DispatchMessageW(&message); + } + + } + + UnregisterClassW(wc.lpszClassName, wc.hInstance); + } + + if (SplashScreenImage) DeleteObject(SplashScreenImage); + + CoUninitialize(); + } + + return 0; +} + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CLOSE: + { + // Ignore closing of the splash screen. + return 0; + } + case WM_SYSCOMMAND: + { + if ((wParam & 0xfff0) == SC_CLOSE) + { + return 0; + } + break; + } + case WM_DESTROY: + { + PostQuitMessage(0); + return 0; + } + } + + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +BOOL SetWindowSplashScreen(HWND window, HBITMAP bitmap) +{ + BOOL result = FALSE; + + BITMAP bitmapInformation; + i_memset(&bitmapInformation, 0, sizeof(bitmapInformation)); + + if (GetObjectW(bitmap, sizeof(bitmapInformation), &bitmapInformation)) + { + MONITORINFO monitorInformation; + i_memset(&monitorInformation, 0, sizeof(monitorInformation)); + monitorInformation.cbSize = sizeof(monitorInformation); + + if (GetMonitorInfoW(MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY), &monitorInformation)) + { + SIZE windowSize; + windowSize.cx = bitmapInformation.bmWidth; + windowSize.cy = bitmapInformation.bmHeight; + + POINT windowPosition; + windowPosition.x = monitorInformation.rcWork.left + (monitorInformation.rcWork.right - monitorInformation.rcWork.left - windowSize.cx) / 2; + windowPosition.y = monitorInformation.rcWork.top + (monitorInformation.rcWork.bottom - monitorInformation.rcWork.top - windowSize.cy) / 2; + + POINT sourcePosition; + sourcePosition.x = 0; + sourcePosition.y = 0; + + BLENDFUNCTION blendFunction; + blendFunction.BlendOp = AC_SRC_OVER; + blendFunction.BlendFlags = 0; + blendFunction.SourceConstantAlpha = 255; + blendFunction.AlphaFormat = AC_SRC_ALPHA; + + HDC screenDc = GetDC(NULL); + if (screenDc) + { + HDC bitmapDc = CreateCompatibleDC(screenDc); + if (bitmapDc) + { + HGDIOBJ oldImage = SelectObject(bitmapDc, bitmap); + UpdateLayeredWindow(window, screenDc, &windowPosition, &windowSize, bitmapDc, &sourcePosition, 0, &blendFunction, ULW_ALPHA); + result = TRUE; + + SelectObject(bitmapDc, oldImage); + DeleteDC(bitmapDc); + } + + ReleaseDC(NULL, screenDc); + } + } + } + + return result; +} +HBITMAP GetImageResource(DWORD resourceID, LPCSTR type) +{ + LPBYTE resourceData; + DWORD resourceSize; + + if (GetResource(resourceID, type, &resourceData, &resourceSize)) + { + HBITMAP bitmap = NULL; + + IWICImagingFactory *factory; + HRESULT result = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, &IID_IWICImagingFactory, (LPVOID*)&factory); + if (SUCCEEDED(result)) + { + IWICStream *stream; + result = IWICImagingFactory_CreateStream(factory, &stream); + if (SUCCEEDED(result)) + { + result = IWICStream_InitializeFromMemory(stream, resourceData, resourceSize); + if (SUCCEEDED(result)) + { + IWICBitmapDecoder *decoder; + result = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream*)stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder); + if (SUCCEEDED(result)) + { + IWICBitmapFrameDecode *frame; + result = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); + if (SUCCEEDED(result)) + { + IWICBitmapSource *convertedSource; + result = WICConvertBitmapSource(&GUID_WICPixelFormat32bppPBGRA, (IWICBitmapSource *)frame, &convertedSource); + if (SUCCEEDED(result)) + { + UINT width; + UINT height; + result = IWICBitmapSource_GetSize(convertedSource, &width, &height); + if (SUCCEEDED(result) && width > 0 && height > 0) + { + BITMAPINFO bitmapInfo; + i_memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = (LONG)width; + bitmapInfo.bmiHeader.biHeight = -(LONG)height; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + + LPVOID pixels; + bitmap = CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, NULL, 0); + + if (bitmap && pixels) + { + result = IWICBitmapSource_CopyPixels(convertedSource, NULL, width * 4, width * 4 * height, (LPBYTE)pixels); + if (FAILED(result)) + { + DeleteObject(bitmap); + bitmap = NULL; + } + } + else if (bitmap) + { + DeleteObject(bitmap); + bitmap = NULL; + } + } + + IWICBitmapSource_Release(convertedSource); + } + + IWICBitmapFrameDecode_Release(frame); + } + + IWICBitmapDecoder_Release(decoder); + } + } + + IWICStream_Release(stream); + } + + IWICImagingFactory_Release(factory); + } + + return bitmap; + } + + return NULL; +} +VOID StartTestConsole(LPCWSTR path) +{ STARTUPINFOW startupInfo; PROCESS_INFORMATION processInformation; i_memset(&startupInfo, 0, sizeof(STARTUPINFOW)); i_memset(&processInformation, 0, sizeof(PROCESS_INFORMATION)); startupInfo.cb = sizeof(startupInfo); - if (!CreateProcessW(targetPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation)) - { - MessageBoxW(NULL, L"Error", L"Test Console", MB_OK | MB_ICONHAND); - return 0; - } - + CreateProcessW(path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation); CloseHandle(processInformation.hThread); CloseHandle(processInformation.hProcess); - - return 0; } \ No newline at end of file diff --git a/TestConsoleLauncher/TestConsoleLauncher.h b/TestConsoleLauncher/TestConsoleLauncher.h new file mode 100644 index 0000000..d5bc42b --- /dev/null +++ b/TestConsoleLauncher/TestConsoleLauncher.h @@ -0,0 +1,11 @@ +#define CUSTOM_ENTRY +#include "r77mindef.h" + +HWND Window; +HBITMAP SplashScreenImage; + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +BOOL SetWindowSplashScreen(HWND window, HBITMAP bitmap); +HBITMAP GetImageResource(DWORD resourceID, LPCSTR type); +VOID StartTestConsole(LPCWSTR path); \ No newline at end of file diff --git a/TestConsoleLauncher/TestConsoleLauncher.rc b/TestConsoleLauncher/TestConsoleLauncher.rc index 7aaddbbce7f963a7381b21f6e5453cc15dd4d7d9..3704cf8e47642f7c9b23e872b333359744ffdf86 100644 GIT binary patch delta 160 zcmX>nxlLxn6wb*R>>IoT82lLA8F(4E81#V Windows true - ntdll.lib;shlwapi.lib;%(AdditionalDependencies) + ntdll.lib;kernel32.lib;advapi32.lib;user32.lib;gdi32.lib;comctl32.lib;shlwapi.lib;ole32.lib;windowscodecs.lib;msimg32.lib;pathcch.lib;%(AdditionalDependencies) true EntryPoint false @@ -95,7 +95,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" Windows false - ntdll.lib;shlwapi.lib;%(AdditionalDependencies) + ntdll.lib;kernel32.lib;advapi32.lib;user32.lib;gdi32.lib;comctl32.lib;shlwapi.lib;ole32.lib;windowscodecs.lib;msimg32.lib;pathcch.lib;%(AdditionalDependencies) true EntryPoint false @@ -114,11 +114,13 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" + + diff --git a/TestConsoleLauncher/resource.h b/TestConsoleLauncher/resource.h index cbb6bbf..cd9d292 100644 --- a/TestConsoleLauncher/resource.h +++ b/TestConsoleLauncher/resource.h @@ -3,12 +3,13 @@ // Used by TestConsoleLauncher.rc // #define IDI_ICON 101 +#define IDB_SPLASHSCREEN 102 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 From 042b8e315e08c4079a1cfbe251deddd9380f9a20 Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Tue, 28 Jul 2026 09:52:34 +0200 Subject: [PATCH 3/4] Refactoring --- Install/{Resource.rc => Install.rc} | 0 Install/Install.vcxproj | 2 +- Install/Install.vcxproj.filters | 44 +++++++++--------- TestConsole/TestConsole.ico | Bin 19828 -> 13071 bytes .../SubControls/ControlPipeUserControl.xaml | 4 +- TestConsoleLauncher/TestConsole.ico | Bin 19828 -> 13071 bytes Uninstall/{Resource.rc => Uninstall.rc} | 0 Uninstall/Uninstall.vcxproj | 2 +- Uninstall/Uninstall.vcxproj.filters | 42 ++++++++--------- 9 files changed, 47 insertions(+), 47 deletions(-) rename Install/{Resource.rc => Install.rc} (100%) rename Uninstall/{Resource.rc => Uninstall.rc} (100%) diff --git a/Install/Resource.rc b/Install/Install.rc similarity index 100% rename from Install/Resource.rc rename to Install/Install.rc diff --git a/Install/Install.vcxproj b/Install/Install.vcxproj index 1de6dfc..f245d1b 100644 --- a/Install/Install.vcxproj +++ b/Install/Install.vcxproj @@ -122,7 +122,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" - + diff --git a/Install/Install.vcxproj.filters b/Install/Install.vcxproj.filters index 418b921..be751f3 100644 --- a/Install/Install.vcxproj.filters +++ b/Install/Install.vcxproj.filters @@ -1,23 +1,23 @@ - - - - - {812009c3-0b86-4444-9ce5-09208fb015db} - - - - - - - - - - - - - - - Resources - - + + + + + {812009c3-0b86-4444-9ce5-09208fb015db} + + + + + + + + + + + + + + + Resources + + \ No newline at end of file diff --git a/TestConsole/TestConsole.ico b/TestConsole/TestConsole.ico index 813fcbf655e37a24f212646fce3977a9c0acb390..814055c2535cce5467ac47008393fc6b08a8e8d7 100644 GIT binary patch delta 156 zcmew|i?Kh=je&uYfrSAC7#S28B-I!gfIwC delta 6834 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 V*|t^vc@^}~YI^7y{ol&uzW@giS-}7R diff --git a/TestConsole/Windows/MainWindow/SubControls/ControlPipeUserControl.xaml b/TestConsole/Windows/MainWindow/SubControls/ControlPipeUserControl.xaml index 382154b..07af561 100644 --- a/TestConsole/Windows/MainWindow/SubControls/ControlPipeUserControl.xaml +++ b/TestConsole/Windows/MainWindow/SubControls/ControlPipeUserControl.xaml @@ -12,8 +12,8 @@ xmlns:cui="http://schemas.bytecode77.com/2025/xaml/cui" DataContext="{Binding ViewModel, ElementName=controlPipeUserControl}"> - - + + diff --git a/TestConsoleLauncher/TestConsole.ico b/TestConsoleLauncher/TestConsole.ico index 813fcbf655e37a24f212646fce3977a9c0acb390..814055c2535cce5467ac47008393fc6b08a8e8d7 100644 GIT binary patch delta 156 zcmew|i?Kh=je&uYfrSAC7#S28B-I!gfIwC delta 6834 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 V*|t^vc@^}~YI^7y{ol&uzW@giS-}7R diff --git a/Uninstall/Resource.rc b/Uninstall/Uninstall.rc similarity index 100% rename from Uninstall/Resource.rc rename to Uninstall/Uninstall.rc diff --git a/Uninstall/Uninstall.vcxproj b/Uninstall/Uninstall.vcxproj index 9f06c3b..c11dd7f 100644 --- a/Uninstall/Uninstall.vcxproj +++ b/Uninstall/Uninstall.vcxproj @@ -111,7 +111,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)$Build" - + diff --git a/Uninstall/Uninstall.vcxproj.filters b/Uninstall/Uninstall.vcxproj.filters index d08a424..83d7422 100644 --- a/Uninstall/Uninstall.vcxproj.filters +++ b/Uninstall/Uninstall.vcxproj.filters @@ -1,22 +1,22 @@ - - - - - {0a2dd5cf-758d-465c-b618-75f299998dd0} - - - - - - - - - - - Resources - - - - - + + + + + {0a2dd5cf-758d-465c-b618-75f299998dd0} + + + + + + + + + + + Resources + + + + + \ No newline at end of file From 2dcf4da223938cd9df4f32fd28da79ceec00ac7e Mon Sep 17 00:00:00 2001 From: Martin Fischer Date: Tue, 28 Jul 2026 22:51:55 +0200 Subject: [PATCH 4/4] TestConsoleLauncher splash screen --- BuildTask/BuildTask.csproj | 2 +- TestConsole/TestConsole.csproj | 4 ++-- TestConsole/Windows/MainWindow/MainWindow.xaml | 2 +- TestConsole/Windows/MainWindow/MainWindowViewModel.cs | 3 +++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/BuildTask/BuildTask.csproj b/BuildTask/BuildTask.csproj index 4039ec0..80b199f 100644 --- a/BuildTask/BuildTask.csproj +++ b/BuildTask/BuildTask.csproj @@ -6,7 +6,7 @@ enable - + diff --git a/TestConsole/TestConsole.csproj b/TestConsole/TestConsole.csproj index 65e11ac..3474d62 100644 --- a/TestConsole/TestConsole.csproj +++ b/TestConsole/TestConsole.csproj @@ -26,8 +26,8 @@ - - + + diff --git a/TestConsole/Windows/MainWindow/MainWindow.xaml b/TestConsole/Windows/MainWindow/MainWindow.xaml index 9c6035c..0a73232 100644 --- a/TestConsole/Windows/MainWindow/MainWindow.xaml +++ b/TestConsole/Windows/MainWindow/MainWindow.xaml @@ -9,7 +9,7 @@ xmlns:cui="http://schemas.bytecode77.com/2025/xaml/cui" xmlns:ctrl="clr-namespace:TestConsole.Controls" DataContext="{Binding ViewModel, ElementName=mainWindow}" - Title="r77 Test Console" Width="1250" Height="800" Padding="0" WindowStartupLocation="CenterScreen" ResizeMode="CanResizeWithGrip" Loaded="MainWindow_Loaded"> + Title="r77 Test Console" Width="1250" Height="800" Padding="0" WindowStartupLocation="CenterScreen" ResizeMode="CanResizeWithGrip" ui:WindowService.DisableTransitions="True" Loaded="MainWindow_Loaded"> diff --git a/TestConsole/Windows/MainWindow/MainWindowViewModel.cs b/TestConsole/Windows/MainWindow/MainWindowViewModel.cs index fb3e76c..7ca91cd 100644 --- a/TestConsole/Windows/MainWindow/MainWindowViewModel.cs +++ b/TestConsole/Windows/MainWindow/MainWindowViewModel.cs @@ -3,6 +3,7 @@ using BytecodeApi.IO; using BytecodeApi.Rest; using BytecodeApi.Wpf; +using BytecodeApi.Wpf.Services; using Global; using System.Diagnostics; using TestConsole.Helper; @@ -139,6 +140,8 @@ await Task.Run(async () => { // TestConsole.exe was not started by the launcher, possibly by explorer. } + + View.Dispatch(() => WindowService.SetDisableTransitions(View, false)); }); } } \ No newline at end of file