感谢各位。 @
ysc3839 参考你提供的方案,解决了很多问题。放出最终版本,还有一些小问题,但是可以正常运行了,欢迎大家指正。
```
#include <Windows.h>
#include <gdiplus.h>
#include <string>
#include <thread>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")
const wchar_t* watermarkText = L"Your Watermark Text";
const int watermarkFontSize = 38;
const int watermarkSpacing = 100;
void DrawWatermarkToBitmap(HWND hwnd, HDC hdc, int width, int height)
{
// 创建位图上下文
HDC memDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
HBITMAP hOldBitmap = static_cast<HBITMAP>(SelectObject(memDC, hBitmap));
// 创建 Graphics 对象
Graphics graphics(memDC);
// 创建字体
FontFamily fontFamily(L"Arial");
Font font(&fontFamily, watermarkFontSize, FontStyleRegular, UnitPixel);
// Create a SolidBrush with the text color
SolidBrush textBrush(Color(128, 255, 0, 0));
// 获取文本尺寸
RectF layoutRect;
graphics.MeasureString(watermarkText, -1, &font, PointF(0, 0), &layoutRect);
// 计算水印文本块的总数以填满整个位图
int numBlocksX = (width + watermarkSpacing) / (static_cast<int>(layoutRect.Width) + watermarkSpacing);
int numBlocksY = (height + watermarkSpacing) / (static_cast<int>(layoutRect.Height) + watermarkSpacing);
// 计算实际的间距
int actualSpacingX = (width - numBlocksX * static_cast<int>(layoutRect.Width)) / (numBlocksX - 1);
int actualSpacingY = (height - numBlocksY * static_cast<int>(layoutRect.Height)) / (numBlocksY - 1);
// 绘制水印文本块
for (int y = 0; y < numBlocksY; y++) {
for (int x = 0; x < numBlocksX; x++) {
int textX = x * (static_cast<int>(layoutRect.Width) + actualSpacingX);
int textY = y * (static_cast<int>(layoutRect.Height) + actualSpacingY);
// 移动 Graphics 对象到文本块位置
graphics.ResetTransform();
graphics.TranslateTransform(static_cast<float>(textX), static_cast<float>(textY));
graphics.RotateTransform(-45.0f);
// 绘制水印文本
graphics.DrawString(watermarkText, -1, &font, PointF(0, 0), &textBrush);
}
}
// 渲染位图到窗口
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
POINT ptSrc = { 0, 0 };
SIZE sizeWnd = { width, height };
POINT ptDst = { 0, 0 };
UpdateLayeredWindow(hwnd, hdc, &ptDst, &sizeWnd, memDC, &ptSrc, 0, &blend, ULW_ALPHA);
// 清理资源
SelectObject(memDC, hOldBitmap);
DeleteObject(hBitmap);
DeleteDC(memDC);
//ReleaseDC(hwnd, hdc);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
SetTimer(hwnd, 1, 1000, NULL); // 创建定时器,每秒更新水印
break;
case WM_TIMER:
{
DrawWatermarkToBitmap(hwnd, GetDC(hwnd), GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
break;
}
case WM_SIZE:
// 窗口大小改变时重新绘制
{
DrawWatermarkToBitmap(hwnd, GetDC(hwnd), GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
break;
}
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// 注册窗口类
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEX));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = L"WatermarkWindowClass";
RegisterClassEx(&wcex);
HWND hwnd = CreateWindowExW(WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST, L"WatermarkWindowClass", L"Watermark Window", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
return 0;
}
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
ShowWindow(hwnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 关闭 GDI+
GdiplusShutdown(gdiplusToken);
return static_cast<int>(msg.wParam);
}
```