- Статус
- Оффлайн
- Регистрация
- 24 Ноя 2024
- Сообщения
- 671
- Реакции
- 11
Есть проблема - нужно рендерить (если так можно сказать в WebView) прозрачный фон, а рисуется белый. Не знаю что делать. Все методы перепробовал. Вот как должно выглядеть (1 фото, без фона белого), а как выглядит на деле (второе фото)
Коды:
Коды:
C++:
#include <windows.h>
#include <windowsx.h>
#include <wrl.h>
#include <wil/com.h>
#include <WebView2.h>
#include <string>
#include <fstream>
#include <sstream>
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
Microsoft::WRL::ComPtr<ICoreWebView2> webView;
Microsoft::WRL::ComPtr<ICoreWebView2Controller> webViewController;
HWND hWnd;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void InitializeWebView();
std::wstring GetExecutableDirectory();
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wcex = {};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszClassName = L"StarCodeLoginWindowClass";
RegisterClassEx(&wcex);
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
int windowWidth = 600;
int windowHeight = 700;
int posX = (screenWidth - windowWidth) / 2;
int posY = (screenHeight - windowHeight) / 2;
hWnd = CreateWindowEx(
WS_EX_APPWINDOW | WS_EX_LAYERED,
L"StarCodeLoginWindowClass",
L"StarCode",
WS_OVERLAPPEDWINDOW,
posX, posY, windowWidth, windowHeight,
nullptr, nullptr, hInstance, nullptr);
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 255, LWA_COLORKEY);
if (!hWnd) {
MessageBox(NULL, L"Ошибка создания окна", L"Ошибка", MB_ICONERROR);
return 1;
}
MARGINS margins = { 0, 0, 0, 1 };
DwmExtendFrameIntoClientArea(hWnd, &margins);
BOOL value = TRUE;
DwmSetWindowAttribute(hWnd, 20, &value, sizeof(value));
BOOL isDarkMode = TRUE;
DwmSetWindowAttribute(hWnd, 19, &isDarkMode, sizeof(isDarkMode));
DWMNCRENDERINGPOLICY policy = DWMNCRP_ENABLED;
DwmSetWindowAttribute(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof(policy));
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
InitializeWebView();
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE:
SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW & ~WS_CAPTION);
SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
break;
case WM_NCCALCSIZE:
if (wParam == TRUE) {
NCCALCSIZE_PARAMS* params = (NCCALCSIZE_PARAMS*)lParam;
params->rgrc[0].top += 1;
return 0;
}
break;
case WM_NCHITTEST: {
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(hwnd, &pt);
RECT rc;
GetClientRect(hwnd, &rc);
if (pt.y < 30) {
return HTCAPTION;
}
LRESULT hit = DefWindowProc(hwnd, uMsg, wParam, lParam);
if (hit == HTCLIENT) return HTCLIENT;
return hit;
}
case WM_SIZE:
if (webViewController) {
RECT bounds;
GetClientRect(hWnd, &bounds);
bounds.top += 1;
webViewController->put_Bounds(bounds);
}
break;
case WM_KEYDOWN:
if (wParam == VK_F12) {
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
std::wstring GetExecutableDirectory() {
wchar_t exePath[MAX_PATH];
GetModuleFileName(NULL, exePath, MAX_PATH);
std::wstring exeDirectory = exePath;
size_t lastSlash = exeDirectory.find_last_of(L"\\");
return exeDirectory.substr(0, lastSlash + 1);
}
void InitializeWebView() {
std::wstring exeDirectory = GetExecutableDirectory();
CreateCoreWebView2EnvironmentWithOptions(
nullptr, exeDirectory.c_str(), nullptr,
Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
[exeDirectory](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {
env->CreateCoreWebView2Controller(hWnd,
Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
[exeDirectory](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {
if (controller) {
webViewController = controller;
webViewController->get_CoreWebView2(&webView);
RECT bounds;
GetClientRect(hWnd, &bounds);
bounds.top += 1;
webViewController->put_Bounds(bounds);
Microsoft::WRL::ComPtr<ICoreWebView2Controller2> controller2;
if (SUCCEEDED(webViewController.As(&controller2))) {
COREWEBVIEW2_COLOR color;
color.A = 0;
color.R = 0;
color.G = 0;
color.B = 0;
controller2->put_DefaultBackgroundColor(color);
}
ICoreWebView2Settings* settings;
webView->get_Settings(&settings);
settings->put_IsScriptEnabled(TRUE);
settings->put_AreDefaultScriptDialogsEnabled(TRUE);
settings->put_IsWebMessageEnabled(TRUE);
webView->add_WebMessageReceived(
Microsoft::WRL::Callback<ICoreWebView2WebMessageReceivedEventHandler>(
[](ICoreWebView2* webview, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT {
wchar_t* messageRaw;
args->TryGetWebMessageAsString(&messageRaw);
std::wstring message(messageRaw);
MessageBox(hWnd, message.c_str(), L"Получены данные", MB_OK);
CoTaskMemFree(messageRaw);
return S_OK;
}
).Get(), nullptr);
try {
settings->put_AreDevToolsEnabled(FALSE);
}
catch (...) {
}
webView->add_NavigationCompleted(
Microsoft::WRL::Callback<ICoreWebView2NavigationCompletedEventHandler>(
[](ICoreWebView2* webview, ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT {
std::wstring script = L"(function() { \
const style = document.createElement('style'); \
style.innerHTML = '* { user-select: none !important; -webkit-user-select: none !important; } \
html, body { background-color: transparent !important; } \
.overlap-group { background-color: #0e1016ee !important; } \
.login, .pass, .login-button { background-color: #0e1016ee !important; } \
.rectangle { background-color: #5950d3ee !important; }'; \
document.head.appendChild(style); \
})();";
webview->ExecuteScript(script.c_str(), nullptr);
return S_OK;
}
).Get(), nullptr);
std::wstring htmlPath = exeDirectory + L"login.html";
std::wstring fileUrl = L"file:///";
fileUrl += htmlPath;
for (size_t i = 8; i < fileUrl.length(); i++) {
if (fileUrl[i] == L'\\') fileUrl[i] = L'/';
}
webView->Navigate(fileUrl.c_str());
}
return S_OK;
}
).Get());
return S_OK;
}
).Get());
}
HTML:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="utf-8" />
<link rel="stylesheet" href="globals.css" />
<link rel="stylesheet" href="style.css" />
<title>Nix Project - Login</title>
<style>
html, body {
background-color: transparent !important;
}
body::before, body::after {
display: none;
}
.overlap-group {
background-color: #0e1016ee !important;
}
.login, .pass, .login-button {
background-color: #0e1016ee !important;
}
.rectangle {
background-color: #5950d3ee !important;
}
</style>
</head>
<body>
<div class="frame">
<div class="overlap-wrapper">
<div class="overlap">
<div class="group">
<form class="overlap-group" id="login-form">
<p class="nix-project">
<span class="text-wrapper">Добро пожаловать в </span> <span class="span">StarCode</span>
</p>
<p class="div">Пожалуйста, введите данные для входа</p>
<div class="login">
<input type="text" class="input-field" placeholder="Логин" required>
</div>
<div class="pass">
<input type="password" class="input-field" placeholder="Пароль" required>
<div class="password-toggle" id="password-toggle">
<svg viewBox="0 0 24 24">
<path class="eye-open" d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle class="eye-open" cx="12" cy="12" r="3"></circle>
<path class="eye-closed" d="M2 12s3-8 10-8 10 8 10 8-3 8-10 8-10-8-10-8z" style="opacity: 0"></path>
<line class="eye-closed" x1="1" y1="1" x2="23" y2="23" style="opacity: 0"></line>
</svg>
</div>
</div>
<button type="submit" class="login-button">
<div class="text-wrapper-3">Войти</div>
</button>
</form>
</div>
<div class="rectangle"></div>
</div>
</div>
</div>
<script>
document.getElementById('login-form').addEventListener('submit', function(event) {
event.preventDefault();
const username = document.querySelector('.login input').value;
const password = document.querySelector('.pass input').value;
window.chrome.webview.postMessage(JSON.stringify({
type: 'login',
username: username,
password: password
}));
});
document.getElementById('password-toggle').addEventListener('click', function() {
const passwordInput = document.querySelector('.pass input');
const eyeOpen = document.querySelectorAll('.eye-open');
const eyeClosed = document.querySelectorAll('.eye-closed');
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
eyeOpen.forEach(el => {
el.style.opacity = '0';
el.style.transform = 'scale(0.8)';
});
eyeClosed.forEach(el => {
el.style.opacity = '1';
el.style.transform = 'scale(1)';
});
} else {
passwordInput.type = 'password';
eyeOpen.forEach(el => {
el.style.opacity = '1';
el.style.transform = 'scale(1)';
});
eyeClosed.forEach(el => {
el.style.opacity = '0';
el.style.transform = 'scale(0.8)';
});
}
});
</script>
<script>
document.addEventListener('keydown', function(e) {
if (e.key === 'F12' || e.keyCode === 123) {
e.preventDefault();
return false;
}
});
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
return false;
});
</script>
</body>
</html>
CSS:
@import url("https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css");
* {
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
background-color: transparent !important;
overflow: hidden;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
button:focus-visible {
outline: 1px solid #4a90e1 !important;
outline: -webkit-focus-ring-color auto 200px !important;
}
a {
text-decoration: none;
}
Есть проблема - нужно рендерить (если так можно сказать в WebView) прозрачный фон, а рисуется белый. Не знаю что делать. Все методы перепробовал. Вот как должно выглядеть (1 фото, без фона белого), а как выглядит на деле (второе фото)
![]()
![]()
Коды:
C++:#include <windows.h> #include <windowsx.h> #include <wrl.h> #include <wil/com.h> #include <WebView2.h> #include <string> #include <fstream> #include <sstream> #include <dwmapi.h> #pragma comment(lib, "dwmapi.lib") Microsoft::WRL::ComPtr<ICoreWebView2> webView; Microsoft::WRL::ComPtr<ICoreWebView2Controller> webViewController; HWND hWnd; LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void InitializeWebView(); std::wstring GetExecutableDirectory(); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex = {}; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WindowProc; wcex.hInstance = hInstance; wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = NULL; wcex.lpszClassName = L"StarCodeLoginWindowClass"; RegisterClassEx(&wcex); int screenWidth = GetSystemMetrics(SM_CXSCREEN); int screenHeight = GetSystemMetrics(SM_CYSCREEN); int windowWidth = 600; int windowHeight = 700; int posX = (screenWidth - windowWidth) / 2; int posY = (screenHeight - windowHeight) / 2; hWnd = CreateWindowEx( WS_EX_APPWINDOW | WS_EX_LAYERED, L"StarCodeLoginWindowClass", L"StarCode", WS_OVERLAPPEDWINDOW, posX, posY, windowWidth, windowHeight, nullptr, nullptr, hInstance, nullptr); SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 255, LWA_COLORKEY); if (!hWnd) { MessageBox(NULL, L"Ошибка создания окна", L"Ошибка", MB_ICONERROR); return 1; } MARGINS margins = { 0, 0, 0, 1 }; DwmExtendFrameIntoClientArea(hWnd, &margins); BOOL value = TRUE; DwmSetWindowAttribute(hWnd, 20, &value, sizeof(value)); BOOL isDarkMode = TRUE; DwmSetWindowAttribute(hWnd, 19, &isDarkMode, sizeof(isDarkMode)); DWMNCRENDERINGPOLICY policy = DWMNCRP_ENABLED; DwmSetWindowAttribute(hWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof(policy)); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); InitializeWebView(); MSG msg = {}; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW & ~WS_CAPTION); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER); break; case WM_NCCALCSIZE: if (wParam == TRUE) { NCCALCSIZE_PARAMS* params = (NCCALCSIZE_PARAMS*)lParam; params->rgrc[0].top += 1; return 0; } break; case WM_NCHITTEST: { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; ScreenToClient(hwnd, &pt); RECT rc; GetClientRect(hwnd, &rc); if (pt.y < 30) { return HTCAPTION; } LRESULT hit = DefWindowProc(hwnd, uMsg, wParam, lParam); if (hit == HTCLIENT) return HTCLIENT; return hit; } case WM_SIZE: if (webViewController) { RECT bounds; GetClientRect(hWnd, &bounds); bounds.top += 1; webViewController->put_Bounds(bounds); } break; case WM_KEYDOWN: if (wParam == VK_F12) { return 0; } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } std::wstring GetExecutableDirectory() { wchar_t exePath[MAX_PATH]; GetModuleFileName(NULL, exePath, MAX_PATH); std::wstring exeDirectory = exePath; size_t lastSlash = exeDirectory.find_last_of(L"\\"); return exeDirectory.substr(0, lastSlash + 1); } void InitializeWebView() { std::wstring exeDirectory = GetExecutableDirectory(); CreateCoreWebView2EnvironmentWithOptions( nullptr, exeDirectory.c_str(), nullptr, Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>( [exeDirectory](HRESULT result, ICoreWebView2Environment* env) -> HRESULT { env->CreateCoreWebView2Controller(hWnd, Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>( [exeDirectory](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT { if (controller) { webViewController = controller; webViewController->get_CoreWebView2(&webView); RECT bounds; GetClientRect(hWnd, &bounds); bounds.top += 1; webViewController->put_Bounds(bounds); Microsoft::WRL::ComPtr<ICoreWebView2Controller2> controller2; if (SUCCEEDED(webViewController.As(&controller2))) { COREWEBVIEW2_COLOR color; color.A = 0; color.R = 0; color.G = 0; color.B = 0; controller2->put_DefaultBackgroundColor(color); } ICoreWebView2Settings* settings; webView->get_Settings(&settings); settings->put_IsScriptEnabled(TRUE); settings->put_AreDefaultScriptDialogsEnabled(TRUE); settings->put_IsWebMessageEnabled(TRUE); webView->add_WebMessageReceived( Microsoft::WRL::Callback<ICoreWebView2WebMessageReceivedEventHandler>( [](ICoreWebView2* webview, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT { wchar_t* messageRaw; args->TryGetWebMessageAsString(&messageRaw); std::wstring message(messageRaw); MessageBox(hWnd, message.c_str(), L"Получены данные", MB_OK); CoTaskMemFree(messageRaw); return S_OK; } ).Get(), nullptr); try { settings->put_AreDevToolsEnabled(FALSE); } catch (...) { } webView->add_NavigationCompleted( Microsoft::WRL::Callback<ICoreWebView2NavigationCompletedEventHandler>( [](ICoreWebView2* webview, ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT { std::wstring script = L"(function() { \ const style = document.createElement('style'); \ style.innerHTML = '* { user-select: none !important; -webkit-user-select: none !important; } \ html, body { background-color: transparent !important; } \ .overlap-group { background-color: #0e1016ee !important; } \ .login, .pass, .login-button { background-color: #0e1016ee !important; } \ .rectangle { background-color: #5950d3ee !important; }'; \ document.head.appendChild(style); \ })();"; webview->ExecuteScript(script.c_str(), nullptr); return S_OK; } ).Get(), nullptr); std::wstring htmlPath = exeDirectory + L"login.html"; std::wstring fileUrl = L"file:///"; fileUrl += htmlPath; for (size_t i = 8; i < fileUrl.length(); i++) { if (fileUrl[i] == L'\\') fileUrl[i] = L'/'; } webView->Navigate(fileUrl.c_str()); } return S_OK; } ).Get()); return S_OK; } ).Get()); }
HTML:<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta charset="utf-8" /> <link rel="stylesheet" href="globals.css" /> <link rel="stylesheet" href="style.css" /> <title>Nix Project - Login</title> <style> html, body { background-color: transparent !important; } body::before, body::after { display: none; } .overlap-group { background-color: #0e1016ee !important; } .login, .pass, .login-button { background-color: #0e1016ee !important; } .rectangle { background-color: #5950d3ee !important; } </style> </head> <body> <div class="frame"> <div class="overlap-wrapper"> <div class="overlap"> <div class="group"> <form class="overlap-group" id="login-form"> <p class="nix-project"> <span class="text-wrapper">Добро пожаловать в </span> <span class="span">StarCode</span> </p> <p class="div">Пожалуйста, введите данные для входа</p> <div class="login"> <input type="text" class="input-field" placeholder="Логин" required> </div> <div class="pass"> <input type="password" class="input-field" placeholder="Пароль" required> <div class="password-toggle" id="password-toggle"> <svg viewBox="0 0 24 24"> <path class="eye-open" d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path> <circle class="eye-open" cx="12" cy="12" r="3"></circle> <path class="eye-closed" d="M2 12s3-8 10-8 10 8 10 8-3 8-10 8-10-8-10-8z" style="opacity: 0"></path> <line class="eye-closed" x1="1" y1="1" x2="23" y2="23" style="opacity: 0"></line> </svg> </div> </div> <button type="submit" class="login-button"> <div class="text-wrapper-3">Войти</div> </button> </form> </div> <div class="rectangle"></div> </div> </div> </div> <script> document.getElementById('login-form').addEventListener('submit', function(event) { event.preventDefault(); const username = document.querySelector('.login input').value; const password = document.querySelector('.pass input').value; window.chrome.webview.postMessage(JSON.stringify({ type: 'login', username: username, password: password })); }); document.getElementById('password-toggle').addEventListener('click', function() { const passwordInput = document.querySelector('.pass input'); const eyeOpen = document.querySelectorAll('.eye-open'); const eyeClosed = document.querySelectorAll('.eye-closed'); if (passwordInput.type === 'password') { passwordInput.type = 'text'; eyeOpen.forEach(el => { el.style.opacity = '0'; el.style.transform = 'scale(0.8)'; }); eyeClosed.forEach(el => { el.style.opacity = '1'; el.style.transform = 'scale(1)'; }); } else { passwordInput.type = 'password'; eyeOpen.forEach(el => { el.style.opacity = '1'; el.style.transform = 'scale(1)'; }); eyeClosed.forEach(el => { el.style.opacity = '0'; el.style.transform = 'scale(0.8)'; }); } }); </script> <script> document.addEventListener('keydown', function(e) { if (e.key === 'F12' || e.keyCode === 123) { e.preventDefault(); return false; } }); document.addEventListener('contextmenu', function(e) { e.preventDefault(); return false; }); </script> </body> </html>
CSS:@import url("https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css"); * { -webkit-font-smoothing: antialiased; box-sizing: border-box; } html, body { margin: 0; padding: 0; height: 100%; width: 100%; background-color: transparent !important; overflow: hidden; } body { display: flex; justify-content: center; align-items: center; } button:focus-visible { outline: 1px solid #4a90e1 !important; outline: -webkit-focus-ring-color auto 200px !important; } a { text-decoration: none; }