init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
107
Telegram/lib_base/base/platform/win/base_battery_saving_win.cpp
Normal file
107
Telegram/lib_base/base/platform/win/base_battery_saving_win.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_battery_saving_win.h"
|
||||
|
||||
#include "base/battery_saving.h"
|
||||
#include "base/integration.h"
|
||||
|
||||
#include <QtCore/QAbstractNativeEventFilter>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
class BatterySaving final
|
||||
: public AbstractBatterySaving
|
||||
, public QAbstractNativeEventFilter {
|
||||
public:
|
||||
BatterySaving(Fn<void()> changedCallback);
|
||||
~BatterySaving();
|
||||
|
||||
std::optional<bool> enabled() const override;
|
||||
|
||||
private:
|
||||
bool nativeEventFilter(
|
||||
const QByteArray &eventType,
|
||||
void *message,
|
||||
native_event_filter_result *result) override;
|
||||
|
||||
QWidget _fake;
|
||||
HWND _hwnd = nullptr;
|
||||
HPOWERNOTIFY _notify = nullptr;
|
||||
Fn<void()> _changedCallback;
|
||||
|
||||
};
|
||||
|
||||
BatterySaving::BatterySaving(Fn<void()> changedCallback)
|
||||
: _changedCallback(std::move(changedCallback)) {
|
||||
if (!_changedCallback) {
|
||||
return;
|
||||
}
|
||||
_fake.hide();
|
||||
_fake.createWinId();
|
||||
const auto window = _fake.windowHandle();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
_hwnd = reinterpret_cast<HWND>(window->winId());
|
||||
if (!_hwnd) {
|
||||
return;
|
||||
}
|
||||
_notify = RegisterPowerSettingNotification(
|
||||
_hwnd,
|
||||
&GUID_POWER_SAVING_STATUS,
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
if (!_notify) {
|
||||
return;
|
||||
}
|
||||
qApp->installNativeEventFilter(this);
|
||||
}
|
||||
|
||||
BatterySaving::~BatterySaving() {
|
||||
if (_notify) {
|
||||
qApp->removeNativeEventFilter(this);
|
||||
UnregisterPowerSettingNotification(_notify);
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<bool> BatterySaving::enabled() const {
|
||||
if (_changedCallback && !_notify) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto status = SYSTEM_POWER_STATUS();
|
||||
if (!GetSystemPowerStatus(&status) || (status.BatteryFlag & 128)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return (status.SystemStatusFlag == 1);
|
||||
}
|
||||
|
||||
bool BatterySaving::nativeEventFilter(
|
||||
const QByteArray &eventType,
|
||||
void *message,
|
||||
native_event_filter_result *result) {
|
||||
Expects(_hwnd != nullptr);
|
||||
|
||||
const auto msg = static_cast<MSG*>(message);
|
||||
if (msg->hwnd == _hwnd && msg->message == WM_POWERBROADCAST) {
|
||||
Integration::Instance().enterFromEventLoop(_changedCallback);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<AbstractBatterySaving> CreateBatterySaving(
|
||||
Fn<void()> changedCallback) {
|
||||
return std::make_unique<BatterySaving>(std::move(changedCallback));
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
@@ -0,0 +1,7 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
247
Telegram/lib_base/base/platform/win/base_file_utilities_win.cpp
Normal file
247
Telegram/lib_base/base/platform/win/base_file_utilities_win.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_file_utilities_win.h"
|
||||
|
||||
#include "base/platform/win/base_windows_safe_library.h"
|
||||
#include "base/platform/win/base_windows_shlobj_h.h"
|
||||
#include "base/algorithm.h"
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <shellapi.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <RestartManager.h>
|
||||
#include <io.h>
|
||||
|
||||
#define LOAD_SYMBOL(lib, name) ::base::Platform::LoadMethod(lib, #name, name)
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
// RSTRTMGR.DLL
|
||||
|
||||
DWORD(__stdcall *RmStartSession)(
|
||||
_Out_ DWORD *pSessionHandle,
|
||||
_Reserved_ DWORD dwSessionFlags,
|
||||
_Out_writes_(CCH_RM_SESSION_KEY + 1) WCHAR strSessionKey[]);
|
||||
DWORD(__stdcall *RmRegisterResources)(
|
||||
_In_ DWORD dwSessionHandle,
|
||||
_In_ UINT nFiles,
|
||||
_In_reads_opt_(nFiles) LPCWSTR rgsFileNames[],
|
||||
_In_ UINT nApplications,
|
||||
_In_reads_opt_(nApplications) RM_UNIQUE_PROCESS rgApplications[],
|
||||
_In_ UINT nServices,
|
||||
_In_reads_opt_(nServices) LPCWSTR rgsServiceNames[]);
|
||||
DWORD(__stdcall *RmGetList)(
|
||||
_In_ DWORD dwSessionHandle,
|
||||
_Out_ UINT *pnProcInfoNeeded,
|
||||
_Inout_ UINT *pnProcInfo,
|
||||
_Inout_updates_opt_(*pnProcInfo) RM_PROCESS_INFO rgAffectedApps[],
|
||||
_Out_ LPDWORD lpdwRebootReasons);
|
||||
DWORD(__stdcall *RmShutdown)(
|
||||
_In_ DWORD dwSessionHandle,
|
||||
_In_ ULONG lActionFlags,
|
||||
_In_opt_ RM_WRITE_STATUS_CALLBACK fnStatus);
|
||||
DWORD(__stdcall *RmEndSession)(
|
||||
_In_ DWORD dwSessionHandle);
|
||||
|
||||
} // namespace
|
||||
|
||||
void ShowInFolder(const QString &filepath) {
|
||||
auto nativePath = QDir::toNativeSeparators(filepath);
|
||||
const auto path = nativePath.toStdWString();
|
||||
if (const auto pidl = ILCreateFromPathW(path.c_str())) {
|
||||
SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0);
|
||||
ILFree(pidl);
|
||||
return;
|
||||
}
|
||||
const auto pathEscaped = nativePath.replace('"', QString("\"\""));
|
||||
const auto command = ("/select," + pathEscaped).toStdWString();
|
||||
ShellExecute(
|
||||
0,
|
||||
0,
|
||||
L"explorer",
|
||||
command.c_str(),
|
||||
0,
|
||||
SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
QString FileNameFromUserString(QString name) {
|
||||
const auto kBadExtensions = { qstr(".lnk"), qstr(".scf") };
|
||||
const auto kMaskExtension = qstr(".download");
|
||||
for (const auto extension : kBadExtensions) {
|
||||
if (name.endsWith(extension, Qt::CaseInsensitive)) {
|
||||
name += kMaskExtension;
|
||||
}
|
||||
}
|
||||
|
||||
static const auto BadNames = {
|
||||
qstr("CON"),
|
||||
qstr("PRN"),
|
||||
qstr("AUX"),
|
||||
qstr("NUL"),
|
||||
qstr("COM1"),
|
||||
qstr("COM2"),
|
||||
qstr("COM3"),
|
||||
qstr("COM4"),
|
||||
qstr("COM5"),
|
||||
qstr("COM6"),
|
||||
qstr("COM7"),
|
||||
qstr("COM8"),
|
||||
qstr("COM9"),
|
||||
qstr("LPT1"),
|
||||
qstr("LPT2"),
|
||||
qstr("LPT3"),
|
||||
qstr("LPT4"),
|
||||
qstr("LPT5"),
|
||||
qstr("LPT6"),
|
||||
qstr("LPT7"),
|
||||
qstr("LPT8"),
|
||||
qstr("LPT9")
|
||||
};
|
||||
for (const auto bad : BadNames) {
|
||||
if (name.startsWith(bad, Qt::CaseInsensitive)) {
|
||||
if (name.size() == bad.size() || name[bad.size()] == '.') {
|
||||
name = '_' + name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
bool DeleteDirectory(QString path) {
|
||||
if (path.endsWith('/')) {
|
||||
path.chop(1);
|
||||
}
|
||||
const auto wide = QDir::toNativeSeparators(path).toStdWString()
|
||||
+ wchar_t(0)
|
||||
+ wchar_t(0);
|
||||
SHFILEOPSTRUCT file_op = {
|
||||
NULL,
|
||||
FO_DELETE,
|
||||
wide.data(),
|
||||
L"",
|
||||
FOF_NOCONFIRMATION |
|
||||
FOF_NOERRORUI |
|
||||
FOF_SILENT,
|
||||
false,
|
||||
0,
|
||||
L""
|
||||
};
|
||||
return (SHFileOperation(&file_op) == 0);
|
||||
}
|
||||
|
||||
void RemoveQuarantine(const QString &path) {
|
||||
}
|
||||
|
||||
QString BundledResourcesPath() {
|
||||
Unexpected("BundledResourcesPath not implemented.");
|
||||
}
|
||||
|
||||
QString CurrentExecutablePath(int argc, char *argv[]) {
|
||||
auto result = std::array<WCHAR, MAX_PATH + 1>{ 0 };
|
||||
const auto count = GetModuleFileName(
|
||||
nullptr,
|
||||
result.data(),
|
||||
MAX_PATH + 1);
|
||||
if (count < MAX_PATH + 1) {
|
||||
const auto info = QFileInfo(QDir::fromNativeSeparators(
|
||||
QString::fromWCharArray(result.data(), count)));
|
||||
return info.absoluteFilePath();
|
||||
}
|
||||
|
||||
// Fallback to the first command line argument.
|
||||
auto argsCount = 0;
|
||||
if (const auto args = CommandLineToArgvW(GetCommandLine(), &argsCount)) {
|
||||
auto info = QFileInfo(QDir::fromNativeSeparators(
|
||||
QString::fromWCharArray(args[0])));
|
||||
LocalFree(args);
|
||||
return info.absoluteFilePath();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool CloseProcesses(const QString &filename) {
|
||||
static const auto loaded = [&] {
|
||||
const auto LibRstrtMgr = SafeLoadLibrary(L"rstrtmgr.dll");
|
||||
return LOAD_SYMBOL(LibRstrtMgr, RmStartSession)
|
||||
&& LOAD_SYMBOL(LibRstrtMgr, RmRegisterResources)
|
||||
&& LOAD_SYMBOL(LibRstrtMgr, RmGetList)
|
||||
&& LOAD_SYMBOL(LibRstrtMgr, RmShutdown)
|
||||
&& LOAD_SYMBOL(LibRstrtMgr, RmEndSession);
|
||||
}();
|
||||
if (!loaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto session = DWORD();
|
||||
auto sessionKey = std::wstring(CCH_RM_SESSION_KEY + 1, wchar_t(0));
|
||||
auto error = RmStartSession(&session, 0, sessionKey.data());
|
||||
if (error != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
const auto guard = gsl::finally([&] { RmEndSession(session); });
|
||||
|
||||
const auto path = QDir::toNativeSeparators(filename).toStdWString();
|
||||
auto nullterm = path.c_str();
|
||||
error = RmRegisterResources(
|
||||
session,
|
||||
1,
|
||||
&nullterm,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr);
|
||||
if (error != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto processInfoNeeded = UINT(0);
|
||||
auto processInfoCount = UINT(0);
|
||||
auto reason = DWORD();
|
||||
|
||||
error = RmGetList(
|
||||
session,
|
||||
&processInfoNeeded,
|
||||
&processInfoCount,
|
||||
nullptr,
|
||||
&reason);
|
||||
if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA) {
|
||||
return false;
|
||||
} else if (processInfoNeeded <= 0) {
|
||||
return true;
|
||||
}
|
||||
error = RmShutdown(session, RmForceShutdown, NULL);
|
||||
if (error != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenameWithOverwrite(const QString &from, const QString &to) {
|
||||
const auto fromPath = QDir::toNativeSeparators(from).toStdWString();
|
||||
const auto toPath = QDir::toNativeSeparators(to).toStdWString();
|
||||
return MoveFileEx(
|
||||
fromPath.c_str(),
|
||||
toPath.c_str(),
|
||||
MOVEFILE_REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
void FlushFileData(QFile &file) {
|
||||
file.flush();
|
||||
if (const auto descriptor = file.handle()) {
|
||||
if (const auto handle = HANDLE(_get_osfhandle(descriptor))) {
|
||||
FlushFileBuffers(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
@@ -0,0 +1,13 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
namespace base::Platform {
|
||||
|
||||
bool CloseProcesses(const QString &filename);
|
||||
|
||||
} // namespace base::Platform
|
||||
@@ -0,0 +1,224 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_global_shortcuts_win.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace base::Platform::GlobalShortcuts {
|
||||
namespace {
|
||||
|
||||
constexpr auto kShiftMouseButton = std::numeric_limits<uint64>::max() - 100;
|
||||
|
||||
HHOOK GlobalHookKeyboard = nullptr;
|
||||
HHOOK GlobalHookMouse = nullptr;
|
||||
HANDLE ThreadHandle = nullptr;
|
||||
HANDLE ThreadEvent = nullptr;
|
||||
DWORD ThreadId = 0;
|
||||
Fn<void(GlobalShortcutKeyGeneric descriptor, bool down)> ProcessCallback;
|
||||
|
||||
[[nodiscard]] GlobalShortcutKeyGeneric MakeDescriptor(
|
||||
uint32 virtualKeyCode,
|
||||
uint32 lParam) {
|
||||
return GlobalShortcutKeyGeneric(
|
||||
(uint64(virtualKeyCode) << 32) | uint64(lParam));
|
||||
}
|
||||
|
||||
[[nodiscard]] GlobalShortcutKeyGeneric MakeMouseDescriptor(uint8 button) {
|
||||
Expects(button > 0 && button < 100);
|
||||
|
||||
return kShiftMouseButton + button;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32 GetVirtualKeyCode(GlobalShortcutKeyGeneric descriptor) {
|
||||
return uint32(uint64(descriptor) >> 32);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32 GetLParam(GlobalShortcutKeyGeneric descriptor) {
|
||||
return uint32(uint64(descriptor) & 0xFFFFFFFFULL);
|
||||
}
|
||||
|
||||
void ProcessHookedKeyboardEvent(WPARAM wParam, LPARAM lParam) {
|
||||
const auto press = (PKBDLLHOOKSTRUCT)lParam;
|
||||
const auto repeatCount = uint32(0);
|
||||
const auto extendedBit = ((press->flags & LLKHF_EXTENDED) != 0);
|
||||
//const auto contextBit = ((press->flags & LLKHF_ALTDOWN) != 0);
|
||||
//const auto transitionState = ((press->flags & LLKHF_UP) != 0);
|
||||
const auto lParamForEvent = (repeatCount & 0x0000FFFFU)
|
||||
| ((uint32(press->scanCode) & 0xFFU) << 16)
|
||||
| (extendedBit ? (uint32(KF_EXTENDED) << 16) : 0);
|
||||
//| (contextBit ? (uint32(KF_ALTDOWN) << 16) : 0); // Alt pressed.
|
||||
//| (transitionState ? (uint32(KF_UP) << 16) : 0); // Is pressed.
|
||||
const auto descriptor = MakeDescriptor(press->vkCode, lParamForEvent);
|
||||
const auto down = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN);
|
||||
|
||||
ProcessCallback(descriptor, down);
|
||||
}
|
||||
|
||||
void ProcessHookedMouseEvent(WPARAM wParam, LPARAM lParam) {
|
||||
if (wParam != WM_RBUTTONDOWN
|
||||
&& wParam != WM_RBUTTONUP
|
||||
&& wParam != WM_MBUTTONDOWN
|
||||
&& wParam != WM_MBUTTONUP
|
||||
&& wParam != WM_XBUTTONDOWN
|
||||
&& wParam != WM_XBUTTONUP) {
|
||||
return;
|
||||
}
|
||||
const auto button = [&] {
|
||||
if (wParam == WM_RBUTTONDOWN || wParam == WM_RBUTTONUP) {
|
||||
return 2;
|
||||
} else if (wParam == WM_MBUTTONDOWN || wParam == WM_MBUTTONUP) {
|
||||
return 3;
|
||||
}
|
||||
const auto press = (PMSLLHOOKSTRUCT)lParam;
|
||||
const auto xbutton = ((press->mouseData >> 16) & 0xFFU);
|
||||
return (xbutton >= 0x01 && xbutton <= 0x18) ? int(xbutton + 3) : 0;
|
||||
}();
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
const auto descriptor = MakeMouseDescriptor(button);
|
||||
const auto down = (wParam == WM_RBUTTONDOWN)
|
||||
|| (wParam == WM_MBUTTONDOWN)
|
||||
|| (wParam == WM_XBUTTONDOWN);
|
||||
|
||||
ProcessCallback(descriptor, down);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK LowLevelKeyboardProc(
|
||||
_In_ int nCode,
|
||||
_In_ WPARAM wParam,
|
||||
_In_ LPARAM lParam) {
|
||||
if (nCode == HC_ACTION) {
|
||||
ProcessHookedKeyboardEvent(wParam, lParam);
|
||||
}
|
||||
return CallNextHookEx(GlobalHookKeyboard, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK LowLevelMouseProc(
|
||||
_In_ int nCode,
|
||||
_In_ WPARAM wParam,
|
||||
_In_ LPARAM lParam) {
|
||||
if (nCode == HC_ACTION) {
|
||||
ProcessHookedMouseEvent(wParam, lParam);
|
||||
}
|
||||
return CallNextHookEx(GlobalHookMouse, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
DWORD WINAPI RunThread(LPVOID) {
|
||||
auto message = MSG();
|
||||
|
||||
// Force message loop creation.
|
||||
PeekMessage(&message, nullptr, WM_USER, WM_USER, PM_NOREMOVE);
|
||||
SetEvent(ThreadEvent);
|
||||
|
||||
const auto guard = gsl::finally([&] {
|
||||
if (GlobalHookKeyboard) {
|
||||
UnhookWindowsHookEx(GlobalHookKeyboard);
|
||||
GlobalHookKeyboard = nullptr;
|
||||
}
|
||||
if (GlobalHookMouse) {
|
||||
UnhookWindowsHookEx(GlobalHookMouse);
|
||||
GlobalHookMouse = nullptr;
|
||||
}
|
||||
});
|
||||
GlobalHookKeyboard = SetWindowsHookEx(
|
||||
WH_KEYBOARD_LL,
|
||||
LowLevelKeyboardProc,
|
||||
nullptr,
|
||||
0);
|
||||
GlobalHookMouse = SetWindowsHookEx(
|
||||
WH_MOUSE_LL,
|
||||
LowLevelMouseProc,
|
||||
nullptr,
|
||||
0);
|
||||
if (!GlobalHookKeyboard || !GlobalHookMouse) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (GetMessage(&message, nullptr, 0, 0)) {
|
||||
if (message.message == WM_QUIT) {
|
||||
break;
|
||||
}
|
||||
TranslateMessage(&message);
|
||||
DispatchMessage(&message);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Available() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Allowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Start(Fn<void(GlobalShortcutKeyGeneric descriptor, bool down)> process) {
|
||||
Expects(!ThreadHandle);
|
||||
Expects(!ThreadId);
|
||||
|
||||
ProcessCallback = std::move(process);
|
||||
ThreadEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
if (!ThreadEvent) {
|
||||
ProcessCallback = nullptr;
|
||||
return;
|
||||
}
|
||||
ThreadHandle = CreateThread(
|
||||
nullptr,
|
||||
0,
|
||||
&RunThread,
|
||||
nullptr,
|
||||
0,
|
||||
&ThreadId);
|
||||
if (!ThreadHandle) {
|
||||
CloseHandle(ThreadEvent);
|
||||
ThreadEvent = nullptr;
|
||||
ThreadId = 0;
|
||||
ProcessCallback = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
if (!ThreadHandle) {
|
||||
return;
|
||||
}
|
||||
WaitForSingleObject(ThreadEvent, INFINITE);
|
||||
PostThreadMessage(ThreadId, WM_QUIT, 0, 0);
|
||||
WaitForSingleObject(ThreadHandle, INFINITE);
|
||||
CloseHandle(ThreadHandle);
|
||||
CloseHandle(ThreadEvent);
|
||||
ThreadHandle = ThreadEvent = nullptr;
|
||||
ThreadId = 0;
|
||||
ProcessCallback = nullptr;
|
||||
}
|
||||
|
||||
QString KeyName(GlobalShortcutKeyGeneric descriptor) {
|
||||
if (descriptor > kShiftMouseButton) {
|
||||
return QString("Mouse %1").arg(descriptor - kShiftMouseButton);
|
||||
}
|
||||
|
||||
constexpr auto kLimit = 1024;
|
||||
|
||||
WCHAR buffer[kLimit + 1] = { 0 };
|
||||
|
||||
// Remove 25 bit, we want to differentiate between left and right Ctrl-s.
|
||||
auto lParam = LONG(GetLParam(descriptor) & ~(1U << 25));
|
||||
|
||||
return GetKeyNameText(lParam, buffer, kLimit)
|
||||
? QString::fromWCharArray(buffer)
|
||||
: (GetVirtualKeyCode(descriptor) == VK_RSHIFT)
|
||||
? QString("Right Shift")
|
||||
: QString("\\x%1").arg(GetVirtualKeyCode(descriptor), 0, 16);
|
||||
}
|
||||
|
||||
bool IsToggleFullScreenKey(not_null<QKeyEvent*> e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace base::Platform::GlobalShortcuts
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:z
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/base_platform_global_shortcuts.h"
|
||||
18
Telegram/lib_base/base/platform/win/base_haptic_win.cpp
Normal file
18
Telegram/lib_base/base/platform/win/base_haptic_win.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_haptic_win.h"
|
||||
|
||||
namespace base::Platform {
|
||||
|
||||
void Haptic() {
|
||||
}
|
||||
|
||||
bool IsSwipeBackEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
9
Telegram/lib_base/base/platform/win/base_haptic_win.h
Normal file
9
Telegram/lib_base/base/platform/win/base_haptic_win.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/base_platform_haptic.h"
|
||||
371
Telegram/lib_base/base/platform/win/base_info_win.cpp
Normal file
371
Telegram/lib_base/base/platform/win/base_info_win.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_info_win.h"
|
||||
|
||||
#include "base/algorithm.h"
|
||||
#include "base/platform/win/base_windows_safe_library.h"
|
||||
|
||||
#include <QtCore/QOperatingSystemVersion>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QDate>
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <windows.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
namespace Platform {
|
||||
namespace {
|
||||
|
||||
decltype(&::IsWow64Process2) IsWow64Process2;
|
||||
|
||||
bool IsWow64Process2Supported() {
|
||||
static const auto Result = [&] {
|
||||
#define LOAD_SYMBOL(lib, name) base::Platform::LoadMethod(lib, #name, name)
|
||||
const auto lib = base::Platform::SafeLoadLibrary(L"Kernel32.dll");
|
||||
return LOAD_SYMBOL(lib, IsWow64Process2);
|
||||
#undef LOAD_SYMBOL
|
||||
}();
|
||||
return Result;
|
||||
}
|
||||
|
||||
QString GetLangCodeById(unsigned int lngId) {
|
||||
const auto primary = (lngId & 0xFFU);
|
||||
switch (primary) {
|
||||
case 0x36: return u"af"_q;
|
||||
case 0x1C: return u"sq"_q;
|
||||
case 0x5E: return u"am"_q;
|
||||
case 0x01: return u"ar"_q;
|
||||
case 0x2B: return u"hy"_q;
|
||||
case 0x4D: return u"as"_q;
|
||||
case 0x2C: return u"az"_q;
|
||||
case 0x45: return u"bn"_q;
|
||||
case 0x6D: return u"ba"_q;
|
||||
case 0x2D: return u"eu"_q;
|
||||
case 0x23: return u"be"_q;
|
||||
case 0x1A:
|
||||
return (lngId == LANG_CROATIAN)
|
||||
? u"hr"_q
|
||||
: (lngId == LANG_BOSNIAN_NEUTRAL || lngId == LANG_BOSNIAN)
|
||||
? u"bs"_q
|
||||
: u"sr"_q;
|
||||
case 0x7E: return u"br"_q;
|
||||
case 0x02: return u"bg"_q;
|
||||
case 0x92: return u"ku"_q;
|
||||
case 0x03: return u"ca"_q;
|
||||
case 0x04: return u"zh"_q;
|
||||
case 0x83: return u"co"_q;
|
||||
case 0x05: return u"cs"_q;
|
||||
case 0x06: return u"da"_q;
|
||||
case 0x65: return u"dv"_q;
|
||||
case 0x13: return u"nl"_q;
|
||||
case 0x09: return u"en"_q;
|
||||
case 0x25: return u"et"_q;
|
||||
case 0x38: return u"fo"_q;
|
||||
case 0x0B: return u"fi"_q;
|
||||
case 0x0c: return u"fr"_q;
|
||||
case 0x62: return u"fy"_q;
|
||||
case 0x56: return u"gl"_q;
|
||||
case 0x37: return u"ka"_q;
|
||||
case 0x07: return u"de"_q;
|
||||
case 0x08: return u"el"_q;
|
||||
case 0x6F: return u"kl"_q;
|
||||
case 0x47: return u"gu"_q;
|
||||
case 0x68: return u"ha"_q;
|
||||
case 0x0D: return u"he"_q;
|
||||
case 0x39: return u"hi"_q;
|
||||
case 0x0E: return u"hu"_q;
|
||||
case 0x0F: return u"is"_q;
|
||||
case 0x70: return u"ig"_q;
|
||||
case 0x21: return u"id"_q;
|
||||
case 0x5D: return u"iu"_q;
|
||||
case 0x3C: return u"ga"_q;
|
||||
case 0x34: return u"xh"_q;
|
||||
case 0x35: return u"zu"_q;
|
||||
case 0x10: return u"it"_q;
|
||||
case 0x11: return u"ja"_q;
|
||||
case 0x4B: return u"kn"_q;
|
||||
case 0x3F: return u"kk"_q;
|
||||
case 0x53: return u"kh"_q;
|
||||
case 0x87: return u"rw"_q;
|
||||
case 0x12: return u"ko"_q;
|
||||
case 0x40: return u"ky"_q;
|
||||
case 0x54: return u"lo"_q;
|
||||
case 0x26: return u"lv"_q;
|
||||
case 0x27: return u"lt"_q;
|
||||
case 0x6E: return u"lb"_q;
|
||||
case 0x2F: return u"mk"_q;
|
||||
case 0x3E: return u"ms"_q;
|
||||
case 0x4C: return u"ml"_q;
|
||||
case 0x3A: return u"mt"_q;
|
||||
case 0x81: return u"mi"_q;
|
||||
case 0x4E: return u"mr"_q;
|
||||
case 0x50: return u"mn"_q;
|
||||
case 0x61: return u"ne"_q;
|
||||
case 0x14: return u"no"_q;
|
||||
case 0x82: return u"oc"_q;
|
||||
case 0x48: return u"or"_q;
|
||||
case 0x63: return u"ps"_q;
|
||||
case 0x29: return u"fa"_q;
|
||||
case 0x15: return u"pl"_q;
|
||||
case 0x16: return u"pt"_q;
|
||||
case 0x67: return u"ff"_q;
|
||||
case 0x46: return u"pa"_q;
|
||||
case 0x18: return u"ro"_q;
|
||||
case 0x17: return u"rm"_q;
|
||||
case 0x19: return u"ru"_q;
|
||||
case 0x3B: return u"se"_q;
|
||||
case 0x4F: return u"sa"_q;
|
||||
case 0x32: return u"tn"_q;
|
||||
case 0x59: return u"sd"_q;
|
||||
case 0x5B: return u"si"_q;
|
||||
case 0x1B: return u"sk"_q;
|
||||
case 0x24: return u"sl"_q;
|
||||
case 0x0A: return u"es"_q;
|
||||
case 0x41: return u"sw"_q;
|
||||
case 0x1D: return u"sv"_q;
|
||||
case 0x28: return u"tg"_q;
|
||||
case 0x49: return u"ta"_q;
|
||||
case 0x44: return u"tt"_q;
|
||||
case 0x4A: return u"te"_q;
|
||||
case 0x1E: return u"th"_q;
|
||||
case 0x51: return u"bo"_q;
|
||||
case 0x73: return u"ti"_q;
|
||||
case 0x1F: return u"tr"_q;
|
||||
case 0x42: return u"tk"_q;
|
||||
case 0x22: return u"uk"_q;
|
||||
case 0x20: return u"ur"_q;
|
||||
case 0x80: return u"ug"_q;
|
||||
case 0x43: return u"uz"_q;
|
||||
case 0x2A: return u"vi"_q;
|
||||
case 0x52: return u"cy"_q;
|
||||
case 0x88: return u"wo"_q;
|
||||
case 0x78: return u"ii"_q;
|
||||
case 0x6A: return u"yo"_q;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QString DeviceModelPretty() {
|
||||
using namespace base::Platform;
|
||||
static const auto result = FinalizeDeviceModel([&] {
|
||||
const auto bios = QSettings(
|
||||
"HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS",
|
||||
QSettings::NativeFormat);
|
||||
const auto value = [&](const char *key) {
|
||||
return SimplifyDeviceModel(bios.value(key).toString());
|
||||
};
|
||||
|
||||
const auto systemProductName = value("SystemProductName");
|
||||
if (const auto model = ProductNameToDeviceModel(systemProductName)
|
||||
; !model.isEmpty()) {
|
||||
return model;
|
||||
}
|
||||
|
||||
const auto systemFamily = value("SystemFamily");
|
||||
const auto baseBoardProduct = value("BaseBoardProduct");
|
||||
const auto familyBoard = SimplifyDeviceModel(
|
||||
systemFamily + ' ' + baseBoardProduct);
|
||||
|
||||
if (IsDeviceModelOk(familyBoard)) {
|
||||
return familyBoard;
|
||||
} else if (IsDeviceModelOk(baseBoardProduct)) {
|
||||
return baseBoardProduct;
|
||||
} else if (IsDeviceModelOk(systemFamily)) {
|
||||
return systemFamily;
|
||||
}
|
||||
return QString();
|
||||
}());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString SystemVersionPretty() {
|
||||
static const auto result = [&] {
|
||||
QStringList resultList;
|
||||
|
||||
if (IsWindows11OrGreater()) {
|
||||
resultList << "Windows 11";
|
||||
} else if (IsWindows10OrGreater()) {
|
||||
resultList << "Windows 10";
|
||||
} else if (IsWindows8Point1OrGreater()) {
|
||||
resultList << "Windows 8.1";
|
||||
} else if (IsWindows8OrGreater()) {
|
||||
resultList << "Windows 8";
|
||||
} else if (IsWindows7OrGreater()) {
|
||||
resultList << "Windows 7";
|
||||
} else {
|
||||
resultList << QSysInfo::prettyProductName();
|
||||
}
|
||||
|
||||
USHORT processMachine, nativeMachine{};
|
||||
if (IsWow64Process2Supported()) {
|
||||
IsWow64Process2(
|
||||
GetCurrentProcess(),
|
||||
&processMachine,
|
||||
&nativeMachine);
|
||||
} else {
|
||||
BOOL isWow64{};
|
||||
IsWow64Process(GetCurrentProcess(), &isWow64);
|
||||
if (isWow64) {
|
||||
nativeMachine = IMAGE_FILE_MACHINE_AMD64;
|
||||
}
|
||||
}
|
||||
|
||||
switch (nativeMachine) {
|
||||
case IMAGE_FILE_MACHINE_AMD64: {
|
||||
resultList << "x64";
|
||||
break;
|
||||
}
|
||||
case IMAGE_FILE_MACHINE_ARM64: {
|
||||
resultList << "arm64";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return resultList.join(' ');
|
||||
}();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString SystemCountry() {
|
||||
auto key = HKEY();
|
||||
const auto result = RegOpenKeyEx(
|
||||
HKEY_CURRENT_USER,
|
||||
L"Control Panel\\International\\Geo",
|
||||
0,
|
||||
KEY_READ,
|
||||
&key);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
constexpr auto kBufSize = 4;
|
||||
auto checkType = DWORD();
|
||||
auto checkSize = DWORD(kBufSize * 2);
|
||||
auto checkStr = std::array<WCHAR, kBufSize>{ 0 };
|
||||
const auto result = RegQueryValueEx(
|
||||
key,
|
||||
L"Name",
|
||||
0,
|
||||
&checkType,
|
||||
reinterpret_cast<BYTE*>(checkStr.data()),
|
||||
&checkSize);
|
||||
if (result == ERROR_SUCCESS && checkSize == 6) { // 2 wchars + null
|
||||
return QString::fromWCharArray(checkStr.data());
|
||||
}
|
||||
}
|
||||
|
||||
int chCount = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, 0, 0);
|
||||
if (chCount && chCount < 128) {
|
||||
WCHAR wstrCountry[128];
|
||||
int len = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, wstrCountry, chCount);
|
||||
if (len) {
|
||||
return QString::fromStdWString(std::wstring(wstrCountry));
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString SystemLanguage() {
|
||||
constexpr auto kMaxLanguageLength = 128;
|
||||
|
||||
auto uiLanguageId = GetUserDefaultUILanguage();
|
||||
auto uiLanguageLength = GetLocaleInfo(uiLanguageId, LOCALE_SNAME, nullptr, 0);
|
||||
if (uiLanguageLength > 0 && uiLanguageLength < kMaxLanguageLength) {
|
||||
WCHAR uiLanguageWideString[kMaxLanguageLength] = { 0 };
|
||||
uiLanguageLength = GetLocaleInfo(uiLanguageId, LOCALE_SNAME, uiLanguageWideString, uiLanguageLength);
|
||||
if (uiLanguageLength <= 0) {
|
||||
return QString();
|
||||
}
|
||||
return QString::fromWCharArray(uiLanguageWideString);
|
||||
}
|
||||
auto uiLanguageCodeLength = GetLocaleInfo(uiLanguageId, LOCALE_ILANGUAGE, nullptr, 0);
|
||||
if (uiLanguageCodeLength > 0 && uiLanguageCodeLength < kMaxLanguageLength) {
|
||||
WCHAR uiLanguageCodeWideString[kMaxLanguageLength] = { 0 };
|
||||
uiLanguageCodeLength = GetLocaleInfo(uiLanguageId, LOCALE_ILANGUAGE, uiLanguageCodeWideString, uiLanguageCodeLength);
|
||||
if (uiLanguageCodeLength <= 0) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
auto languageCode = 0U;
|
||||
for (auto i = 0; i != uiLanguageCodeLength; ++i) {
|
||||
auto ch = uiLanguageCodeWideString[i];
|
||||
if (!ch) {
|
||||
break;
|
||||
}
|
||||
languageCode *= 0x10U;
|
||||
if (ch >= WCHAR('0') && ch <= WCHAR('9')) {
|
||||
languageCode += static_cast<unsigned>(int(ch) - int(WCHAR('0')));
|
||||
} else if (ch >= WCHAR('A') && ch <= WCHAR('F')) {
|
||||
languageCode += static_cast<unsigned>(0x0A + int(ch) - int(WCHAR('A')));
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
return GetLangCodeById(languageCode);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QDate WhenSystemBecomesOutdated() {
|
||||
return QDate();
|
||||
}
|
||||
|
||||
int AutoUpdateVersion() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
QString AutoUpdateKey() {
|
||||
if (IsWindowsARM64()) {
|
||||
return "winarm";
|
||||
} else if (IsWindows64Bit()) {
|
||||
return "win64";
|
||||
} else {
|
||||
return "win";
|
||||
}
|
||||
}
|
||||
|
||||
bool IsWindows7OrGreater() {
|
||||
static const auto result = ::IsWindows7OrGreater();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsWindows8OrGreater() {
|
||||
static const auto result = ::IsWindows8OrGreater();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsWindows8Point1OrGreater() {
|
||||
static const auto result = ::IsWindows8Point1OrGreater();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsWindows10OrGreater() {
|
||||
static const auto result = ::IsWindows10OrGreater();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsWindows11OrGreater() {
|
||||
static const auto result = [&] {
|
||||
if (!IsWindows10OrGreater()) {
|
||||
return false;
|
||||
}
|
||||
const auto version = QOperatingSystemVersion::current();
|
||||
return (version.majorVersion() > 10)
|
||||
|| (version.microVersion() >= 22000);
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
void Start(QJsonObject settings) {
|
||||
SetDllDirectory(L"");
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
69
Telegram/lib_base/base/platform/win/base_info_win.h
Normal file
69
Telegram/lib_base/base/platform/win/base_info_win.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/base_platform_info.h"
|
||||
|
||||
namespace Platform {
|
||||
|
||||
inline OutdateReason WhySystemBecomesOutdated() {
|
||||
return OutdateReason::IsOld;
|
||||
}
|
||||
|
||||
inline constexpr bool IsWindows() {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline constexpr bool IsWindows32Bit() {
|
||||
#ifdef Q_PROCESSOR_X86_32
|
||||
return true;
|
||||
#else // Q_PROCESSOR_X86_32
|
||||
return false;
|
||||
#endif // Q_PROCESSOR_X86_32
|
||||
}
|
||||
|
||||
inline constexpr bool IsWindows64Bit() {
|
||||
#ifdef Q_PROCESSOR_X86_64
|
||||
return true;
|
||||
#else // Q_PROCESSOR_X86_64
|
||||
return false;
|
||||
#endif // Q_PROCESSOR_X86_64
|
||||
}
|
||||
|
||||
inline constexpr bool IsWindowsARM64() {
|
||||
#ifdef Q_PROCESSOR_ARM_64
|
||||
return true;
|
||||
#else // Q_PROCESSOR_ARM_64
|
||||
return false;
|
||||
#endif // Q_PROCESSOR_ARM_64
|
||||
}
|
||||
|
||||
inline constexpr bool IsWindowsStoreBuild() {
|
||||
#ifdef OS_WIN_STORE
|
||||
return true;
|
||||
#else // OS_WIN_STORE
|
||||
return false;
|
||||
#endif // OS_WIN_STORE
|
||||
}
|
||||
|
||||
inline constexpr bool IsMac() { return false; }
|
||||
inline constexpr bool IsMacStoreBuild() { return false; }
|
||||
inline bool IsMac10_12OrGreater() { return false; }
|
||||
inline bool IsMac10_13OrGreater() { return false; }
|
||||
inline bool IsMac10_14OrGreater() { return false; }
|
||||
inline bool IsMac10_15OrGreater() { return false; }
|
||||
inline bool IsMac11_0OrGreater() { return false; }
|
||||
inline bool IsMac26_0OrGreater() { return false; }
|
||||
inline constexpr bool IsLinux() { return false; }
|
||||
inline bool IsX11() { return false; }
|
||||
inline bool IsWayland() { return false; }
|
||||
inline bool IsXwayland() { return false; }
|
||||
inline QString GetLibcName() { return QString(); }
|
||||
inline QString GetLibcVersion() { return QString(); }
|
||||
inline QString GetWindowManager() { return QString(); }
|
||||
|
||||
} // namespace Platform
|
||||
71
Telegram/lib_base/base/platform/win/base_last_input_win.cpp
Normal file
71
Telegram/lib_base/base/platform/win/base_last_input_win.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_last_input_win.h"
|
||||
|
||||
#include "base/call_delayed.h"
|
||||
#include "base/integration.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
constexpr auto kRefreshBadLastUserInputTimeout = 10 * crl::time(1000);
|
||||
|
||||
} // namespace
|
||||
|
||||
std::optional<crl::time> LastUserInputTime() {
|
||||
auto lii = LASTINPUTINFO{ 0 };
|
||||
lii.cbSize = sizeof(LASTINPUTINFO);
|
||||
if (!GetLastInputInfo(&lii)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto now = crl::now();
|
||||
const auto input = crl::time(lii.dwTime);
|
||||
static auto LastTrackedInput = input;
|
||||
static auto LastTrackedWhen = now;
|
||||
|
||||
const auto ticks32 = crl::time(GetTickCount());
|
||||
const auto ticks64 = crl::time(GetTickCount64());
|
||||
const auto elapsed = std::max(ticks32, ticks64) - input;
|
||||
const auto good = (std::abs(ticks32 - ticks64) <= crl::time(1000))
|
||||
&& (elapsed >= 0);
|
||||
if (good) {
|
||||
LastTrackedInput = input;
|
||||
LastTrackedWhen = now;
|
||||
return (now > elapsed) ? (now - elapsed) : crl::time(0);
|
||||
}
|
||||
|
||||
static auto WaitingDelayed = false;
|
||||
if (!WaitingDelayed) {
|
||||
WaitingDelayed = true;
|
||||
base::call_delayed(kRefreshBadLastUserInputTimeout, [=] {
|
||||
WaitingDelayed = false;
|
||||
[[maybe_unused]] const auto cheked = LastUserInputTime();
|
||||
});
|
||||
}
|
||||
constexpr auto OverrunLimit = std::numeric_limits<DWORD>::max();
|
||||
constexpr auto OverrunThreshold = OverrunLimit / 4;
|
||||
if (LastTrackedInput == input) {
|
||||
return LastTrackedWhen;
|
||||
}
|
||||
const auto guard = gsl::finally([&] {
|
||||
LastTrackedInput = input;
|
||||
LastTrackedWhen = now;
|
||||
});
|
||||
if (input > LastTrackedInput) {
|
||||
const auto add = input - LastTrackedInput;
|
||||
return std::min(LastTrackedWhen + add, now);
|
||||
} else if (crl::time(OverrunLimit) + input - LastTrackedInput
|
||||
< crl::time(OverrunThreshold)) {
|
||||
const auto add = crl::time(OverrunLimit) + input - LastTrackedInput;
|
||||
return std::min(LastTrackedWhen + add, now);
|
||||
}
|
||||
return LastTrackedWhen;
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/base_platform_last_input.h"
|
||||
@@ -0,0 +1,59 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_layout_switch_win.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <WinUser.h>
|
||||
#include <minwindef.h>
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxLayoutsCount = 1024;
|
||||
|
||||
} // namespace
|
||||
|
||||
bool SwitchKeyboardLayoutToEnglish() {
|
||||
auto listSize = 0;
|
||||
listSize = GetKeyboardLayoutList(0, nullptr);
|
||||
if (!listSize || listSize > kMaxLayoutsCount) {
|
||||
return false;
|
||||
}
|
||||
auto list = std::vector<HKL>(listSize, nullptr);
|
||||
GetKeyboardLayoutList(list.size(), list.data());
|
||||
auto selectedLayout = HKL();
|
||||
auto selectedLevel = 0;
|
||||
const auto offer = [&](HKL layout, int level) {
|
||||
if (level > selectedLevel) {
|
||||
selectedLayout = layout;
|
||||
selectedLevel = level;
|
||||
}
|
||||
};
|
||||
for (const auto layout : list) {
|
||||
const auto languageId = reinterpret_cast<quintptr>(layout) & 0xFFFF;
|
||||
const auto primaryId = languageId & 0x03FF;
|
||||
const auto sublanguageId = (languageId >> 10);
|
||||
if (primaryId == LANG_ENGLISH) {
|
||||
if (sublanguageId == SUBLANG_ENGLISH_US) {
|
||||
offer(layout, 3);
|
||||
} else if (sublanguageId == SUBLANG_ENGLISH_UK) {
|
||||
offer(layout, 2);
|
||||
} else {
|
||||
offer(layout, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!selectedLayout) {
|
||||
return false;
|
||||
}
|
||||
const auto previous = ActivateKeyboardLayout(
|
||||
selectedLayout,
|
||||
KLF_SETFORPROCESS);
|
||||
return (previous != nullptr);
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
@@ -0,0 +1,8 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/base_platform_network_reachability.h"
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
|
||||
namespace base::Platform {
|
||||
|
||||
std::unique_ptr<NetworkReachability> NetworkReachability::Create() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
#else // Qt >= 6.2.0
|
||||
#include "base/debug_log.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <wrl/client.h>
|
||||
#include <netlistmgr.h>
|
||||
#include <comdef.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
QString ErrorStringFromHResult(HRESULT hr) {
|
||||
_com_error error(hr);
|
||||
return QString::fromWCharArray(error.ErrorMessage());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject) {
|
||||
if (riid == __uuidof(T)) {
|
||||
*ppvObject = static_cast<T *>(from);
|
||||
from->AddRef();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class NetworkListManagerEvents : public INetworkListManagerEvents {
|
||||
public:
|
||||
NetworkListManagerEvents() = default;
|
||||
virtual ~NetworkListManagerEvents() = default;
|
||||
|
||||
bool start();
|
||||
void finish();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void **ppvObject) override;
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return ++_ref; }
|
||||
ULONG STDMETHODCALLTYPE Release() override {
|
||||
if (--_ref == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return _ref;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ConnectivityChanged(
|
||||
NLM_CONNECTIVITY newConnectivity) override;
|
||||
|
||||
rpl::variable<bool> available;
|
||||
|
||||
private:
|
||||
ComPtr<INetworkListManager> _networkListManager = nullptr;
|
||||
ComPtr<IConnectionPoint> _connectionPoint = nullptr;
|
||||
|
||||
std::atomic<ULONG> _ref = 0;
|
||||
DWORD _cookie = 0;
|
||||
|
||||
};
|
||||
|
||||
bool NetworkListManagerEvents::start() {
|
||||
auto hr = CoCreateInstance(
|
||||
CLSID_NetworkListManager,
|
||||
nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_INetworkListManager,
|
||||
&_networkListManager);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
LOG(("NetworkListManagerEvents: "
|
||||
"Could not get a NetworkListManager instance: %1").arg(
|
||||
ErrorStringFromHResult(hr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
ComPtr<IConnectionPointContainer> connectionPointContainer;
|
||||
hr = _networkListManager.As(&connectionPointContainer);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = connectionPointContainer->FindConnectionPoint(
|
||||
IID_INetworkListManagerEvents,
|
||||
&_connectionPoint);
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
LOG(("NetworkListManagerEvents: Failed to get connection point for "
|
||||
"network list manager events: %1").arg(
|
||||
ErrorStringFromHResult(hr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = _connectionPoint->Advise(this, &_cookie);
|
||||
if (FAILED(hr)) {
|
||||
LOG(("NetworkListManagerEvents: "
|
||||
"Failed to subscribe to network connectivity events: %1").arg(
|
||||
ErrorStringFromHResult(hr)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update connectivity since it might have
|
||||
// changed since this class was constructed
|
||||
NLM_CONNECTIVITY connectivity;
|
||||
hr = _networkListManager->GetConnectivity(&connectivity);
|
||||
if (FAILED(hr)) {
|
||||
LOG(("NetworkListManagerEvents: Could not get connectivity: %1").arg(
|
||||
ErrorStringFromHResult(hr)));
|
||||
return false;
|
||||
}
|
||||
available = connectivity != NLM_CONNECTIVITY_DISCONNECTED;
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkListManagerEvents::finish() {
|
||||
if (_connectionPoint) {
|
||||
auto hr = _connectionPoint->Unadvise(_cookie);
|
||||
if (FAILED(hr)) {
|
||||
LOG(("NetworkListManagerEvents: "
|
||||
"Failed to unsubscribe from "
|
||||
"network connectivity events: %1").arg(
|
||||
ErrorStringFromHResult(hr)));
|
||||
} else {
|
||||
_cookie = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE NetworkListManagerEvents::QueryInterface(
|
||||
REFIID riid,
|
||||
void **ppvObject) {
|
||||
if (!ppvObject) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject)
|
||||
|| QueryInterfaceImpl<INetworkListManagerEvents>(
|
||||
this,
|
||||
riid,
|
||||
ppvObject)
|
||||
? S_OK
|
||||
: E_NOINTERFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE NetworkListManagerEvents::ConnectivityChanged(
|
||||
NLM_CONNECTIVITY newConnectivity) {
|
||||
// This function is run on a different thread than 'monitor'
|
||||
// is created on, so we need to run it on that thread
|
||||
available = newConnectivity != NLM_CONNECTIVITY_DISCONNECTED;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class NetworkReachabilityImpl : public NetworkReachability {
|
||||
public:
|
||||
NetworkReachabilityImpl() {
|
||||
const auto hr = CoInitialize(nullptr);
|
||||
if (FAILED(hr)) {
|
||||
LOG(("NetworkReachabilityImpl: Failed to initialize COM: %1").arg(
|
||||
ErrorStringFromHResult(hr)));
|
||||
_comInitFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_managerEvents = new NetworkListManagerEvents();
|
||||
_valid = _managerEvents->start();
|
||||
}
|
||||
|
||||
~NetworkReachabilityImpl() {
|
||||
if (!_comInitFailed) {
|
||||
_managerEvents->finish();
|
||||
_managerEvents = nullptr;
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return _valid;
|
||||
}
|
||||
|
||||
rpl::producer<bool> availableValue() const override {
|
||||
return _managerEvents->available.value();
|
||||
}
|
||||
|
||||
private:
|
||||
ComPtr<NetworkListManagerEvents> _managerEvents = nullptr;
|
||||
bool _comInitFailed = false;
|
||||
bool _valid = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<NetworkReachability> NetworkReachability::Create() {
|
||||
auto result = std::make_unique<NetworkReachabilityImpl>();
|
||||
if (!result->valid()) {
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
#endif // Qt < 6.2.0
|
||||
@@ -0,0 +1,92 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_power_save_blocker_win.h"
|
||||
|
||||
#include "base/platform/base_platform_info.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// Thanks Chromium: services/device/wake_lock/power_save_blocker
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
using namespace ::Platform;
|
||||
|
||||
HANDLE GlobalHandles[kPowerSaveBlockTypeCount];
|
||||
|
||||
HANDLE CreatePowerRequest(
|
||||
POWER_REQUEST_TYPE type,
|
||||
const QString &description) {
|
||||
if (type == PowerRequestExecutionRequired && !IsWindows8OrGreater()) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
auto context = REASON_CONTEXT{ 0 };
|
||||
context.Version = POWER_REQUEST_CONTEXT_VERSION;
|
||||
context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
|
||||
|
||||
auto wide = description.toStdWString();
|
||||
wide.push_back(wchar_t(0)); // So that .data() will be 0-terminated.
|
||||
context.Reason.SimpleReasonString = wide.data();
|
||||
|
||||
const auto handle = ::PowerCreateRequest(&context);
|
||||
if (!handle || handle == INVALID_HANDLE_VALUE) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (::PowerSetRequest(handle, type)) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Something went wrong.
|
||||
CloseHandle(handle);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// Takes ownership of the |handle|.
|
||||
void DeletePowerRequest(POWER_REQUEST_TYPE type, HANDLE handle) {
|
||||
if (!handle || handle == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
} else if (type == PowerRequestExecutionRequired
|
||||
&& !IsWindows8OrGreater()) {
|
||||
return;
|
||||
}
|
||||
::PowerClearRequest(handle, type);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
POWER_REQUEST_TYPE RequestType(PowerSaveBlockType type) {
|
||||
if (type == PowerSaveBlockType::PreventDisplaySleep) {
|
||||
return PowerRequestDisplayRequired;
|
||||
} else if (!IsWindows8OrGreater()) {
|
||||
return PowerRequestSystemRequired;
|
||||
}
|
||||
return PowerRequestExecutionRequired;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void BlockPowerSave(
|
||||
PowerSaveBlockType type,
|
||||
const QString &description,
|
||||
QPointer<QWindow> window) {
|
||||
Expects(!GlobalHandles[PowerSaveBlockTypeIndex(type)]);
|
||||
|
||||
const auto requestType = RequestType(type);
|
||||
GlobalHandles[PowerSaveBlockTypeIndex(type)] = CreatePowerRequest(
|
||||
requestType,
|
||||
description);
|
||||
}
|
||||
|
||||
void UnblockPowerSave(PowerSaveBlockType type, QPointer<QWindow> window) {
|
||||
DeletePowerRequest(
|
||||
RequestType(type),
|
||||
base::take(GlobalHandles[PowerSaveBlockTypeIndex(type)]));
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/base_platform_power_save_blocker.h"
|
||||
51
Telegram/lib_base/base/platform/win/base_process_win.cpp
Normal file
51
Telegram/lib_base/base/platform/win/base_process_win.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_process_win.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
struct FullWindowId {
|
||||
int64 pid = 0;
|
||||
WId windowId = 0;
|
||||
};
|
||||
|
||||
BOOL CALLBACK ActivateProcess(HWND hWnd, LPARAM lParam) {
|
||||
const auto fullId = reinterpret_cast<const FullWindowId*>(lParam);
|
||||
if (reinterpret_cast<WId>(hWnd) != fullId->windowId) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD dwProcessId;
|
||||
::GetWindowThreadProcessId(hWnd, &dwProcessId);
|
||||
|
||||
if (static_cast<int64>(dwProcessId) != fullId->pid) {
|
||||
return TRUE;
|
||||
}
|
||||
::SetForegroundWindow(hWnd);
|
||||
::SetFocus(hWnd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ActivateProcessWindow(int64 pid, WId windowId) {
|
||||
const auto fullId = FullWindowId{ pid, windowId };
|
||||
::EnumWindows(
|
||||
reinterpret_cast<WNDENUMPROC>(ActivateProcess),
|
||||
reinterpret_cast<LPARAM>(&fullId));
|
||||
}
|
||||
|
||||
void ActivateThisProcessWindow(WId windowId) {
|
||||
if (const auto handle = reinterpret_cast<HWND>(windowId)) {
|
||||
::SetFocus(handle);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
9
Telegram/lib_base/base/platform/win/base_process_win.h
Normal file
9
Telegram/lib_base/base/platform/win/base_process_win.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/base_platform_process.h"
|
||||
@@ -0,0 +1,356 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/base_platform_system_media_controls.h"
|
||||
|
||||
#include <unknwn.h> // Conversion from winrt::guid_of to GUID.
|
||||
|
||||
#include "base/integration.h"
|
||||
#include "base/platform/win/base_info_win.h"
|
||||
#include "base/platform/win/base_windows_winrt.h"
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Media.h>
|
||||
#include <winrt/Windows.Storage.Streams.h>
|
||||
|
||||
#include <systemmediatransportcontrolsinterop.h>
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QAbstractNativeEventFilter>
|
||||
#include <QtGui/QImage>
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
namespace winrt {
|
||||
namespace Streams {
|
||||
using namespace Windows::Storage::Streams;
|
||||
} // namespace Streams
|
||||
namespace Media {
|
||||
using namespace Windows::Media;
|
||||
} // namespace Media
|
||||
} // namespace winrt
|
||||
|
||||
namespace base::Platform {
|
||||
|
||||
struct SystemMediaControls::Private : QAbstractNativeEventFilter {
|
||||
using IReferenceStatics
|
||||
= winrt::Streams::IRandomAccessStreamReferenceStatics;
|
||||
Private()
|
||||
: controls(nullptr)
|
||||
, referenceStatics(winrt::get_activation_factory
|
||||
<winrt::Streams::RandomAccessStreamReference,
|
||||
IReferenceStatics>()) {
|
||||
}
|
||||
|
||||
bool nativeEventFilter(
|
||||
const QByteArray &eventType,
|
||||
void *message,
|
||||
native_event_filter_result *result) override;
|
||||
|
||||
QWidget parent;
|
||||
HWND hwnd = nullptr;
|
||||
winrt::Media::SystemMediaTransportControls controls;
|
||||
winrt::Media::ISystemMediaTransportControlsDisplayUpdater displayUpdater;
|
||||
winrt::Media::IMusicDisplayProperties displayProperties;
|
||||
winrt::Streams::DataWriter iconDataWriter;
|
||||
const IReferenceStatics referenceStatics;
|
||||
winrt::event_token eventToken;
|
||||
bool initialized = false;
|
||||
|
||||
rpl::event_stream<SystemMediaControls::Command> commandRequests;
|
||||
};
|
||||
|
||||
bool SystemMediaControls::Private::nativeEventFilter(
|
||||
const QByteArray &eventType,
|
||||
void *message,
|
||||
native_event_filter_result *result) {
|
||||
Expects(hwnd != nullptr);
|
||||
|
||||
const auto msg = static_cast<MSG*>(message);
|
||||
if (msg->hwnd == hwnd
|
||||
&& msg->message == WM_NCACTIVATE
|
||||
&& msg->wParam) {
|
||||
base::Integration::Instance().enterFromEventLoop([&] {
|
||||
commandRequests.fire(Command::Raise);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
winrt::Media::MediaPlaybackStatus SmtcPlaybackStatus(
|
||||
SystemMediaControls::PlaybackStatus status) {
|
||||
switch (status) {
|
||||
case SystemMediaControls::PlaybackStatus::Playing:
|
||||
return winrt::Media::MediaPlaybackStatus::Playing;
|
||||
case SystemMediaControls::PlaybackStatus::Paused:
|
||||
return winrt::Media::MediaPlaybackStatus::Paused;
|
||||
case SystemMediaControls::PlaybackStatus::Stopped:
|
||||
return winrt::Media::MediaPlaybackStatus::Stopped;
|
||||
}
|
||||
Unexpected("SmtcPlaybackStatus in SystemMediaControls");
|
||||
}
|
||||
|
||||
|
||||
auto SMTCButtonToCommand(
|
||||
winrt::Media::SystemMediaTransportControlsButton button) {
|
||||
using SMTCButton = winrt::Media::SystemMediaTransportControlsButton;
|
||||
using Command = SystemMediaControls::Command;
|
||||
|
||||
switch (button) {
|
||||
case SMTCButton::Play:
|
||||
return Command::Play;
|
||||
case SMTCButton::Pause:
|
||||
return Command::Pause;
|
||||
case SMTCButton::Next:
|
||||
return Command::Next;
|
||||
case SMTCButton::Previous:
|
||||
return Command::Previous;
|
||||
case SMTCButton::Stop:
|
||||
return Command::Stop;
|
||||
case SMTCButton::Record:
|
||||
case SMTCButton::FastForward:
|
||||
case SMTCButton::Rewind:
|
||||
case SMTCButton::ChannelUp:
|
||||
case SMTCButton::ChannelDown:
|
||||
return Command::None;
|
||||
}
|
||||
return Command::None;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SystemMediaControls::SystemMediaControls()
|
||||
: _private(std::make_unique<Private>()) {
|
||||
}
|
||||
|
||||
SystemMediaControls::~SystemMediaControls() {
|
||||
if (_private->eventToken) {
|
||||
_private->controls.ButtonPressed(base::take(_private->eventToken));
|
||||
clearMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemMediaControls::init() {
|
||||
if (_private->initialized) {
|
||||
return _private->initialized;
|
||||
}
|
||||
_private->parent.hide();
|
||||
_private->parent.createWinId();
|
||||
const auto window = _private->parent.windowHandle();
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Should be moved to separated file.
|
||||
const auto hwnd = reinterpret_cast<HWND>(window->winId());
|
||||
if (!hwnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto interop = WinRT::Try([&] {
|
||||
return winrt::get_activation_factory<
|
||||
winrt::Media::SystemMediaTransportControls,
|
||||
ISystemMediaTransportControlsInterop>();
|
||||
}).value_or(nullptr);
|
||||
if (!interop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
winrt::com_ptr<winrt::Media::ISystemMediaTransportControls> icontrols;
|
||||
auto hr = interop->GetForWindow(
|
||||
hwnd,
|
||||
winrt::guid_of<winrt::Media::ISystemMediaTransportControls>(),
|
||||
icontrols.put_void());
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_private->controls = winrt::Media::SystemMediaTransportControls(
|
||||
icontrols.detach(),
|
||||
winrt::take_ownership_from_abi);
|
||||
|
||||
using ButtonsEventArgs =
|
||||
winrt::Media::SystemMediaTransportControlsButtonPressedEventArgs;
|
||||
const auto result = WinRT::Try([&] {
|
||||
// Buttons handler.
|
||||
_private->eventToken = _private->controls.ButtonPressed([=](
|
||||
const auto &sender,
|
||||
const ButtonsEventArgs &args) {
|
||||
// This lambda is called in a non-main thread.
|
||||
crl::on_main([=] {
|
||||
const auto button = WinRT::Try([&] {
|
||||
return SMTCButtonToCommand(args.Button());
|
||||
}).value_or(SystemMediaControls::Command::None);
|
||||
_private->commandRequests.fire_copy(button);
|
||||
});
|
||||
});
|
||||
|
||||
_private->controls.IsEnabled(true);
|
||||
|
||||
auto displayUpdater = _private->controls.DisplayUpdater();
|
||||
displayUpdater.Type(winrt::Media::MediaPlaybackType::Music);
|
||||
_private->displayProperties = displayUpdater.MusicProperties();
|
||||
_private->displayUpdater = std::move(displayUpdater);
|
||||
});
|
||||
|
||||
_private->initialized = result;
|
||||
if (result) {
|
||||
_private->hwnd = hwnd;
|
||||
qApp->installNativeEventFilter(_private.get());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SystemMediaControls::setApplicationName(const QString &name) {
|
||||
}
|
||||
|
||||
void SystemMediaControls::setEnabled(bool enabled) {
|
||||
WinRT::Try([&] { _private->controls.IsEnabled(enabled); });
|
||||
}
|
||||
|
||||
void SystemMediaControls::setIsNextEnabled(bool value) {
|
||||
WinRT::Try([&] { _private->controls.IsNextEnabled(value); });
|
||||
}
|
||||
|
||||
void SystemMediaControls::setIsPreviousEnabled(bool value) {
|
||||
WinRT::Try([&] { _private->controls.IsPreviousEnabled(value); });
|
||||
}
|
||||
|
||||
void SystemMediaControls::setIsPlayPauseEnabled(bool value) {
|
||||
WinRT::Try([&] {
|
||||
_private->controls.IsPlayEnabled(value);
|
||||
_private->controls.IsPauseEnabled(value);
|
||||
});
|
||||
}
|
||||
|
||||
void SystemMediaControls::setIsStopEnabled(bool value) {
|
||||
WinRT::Try([&] { _private->controls.IsStopEnabled(value); });
|
||||
}
|
||||
|
||||
void SystemMediaControls::setPlaybackStatus(
|
||||
SystemMediaControls::PlaybackStatus status) {
|
||||
WinRT::Try([&] {
|
||||
_private->controls.PlaybackStatus(SmtcPlaybackStatus(status));
|
||||
});
|
||||
}
|
||||
|
||||
void SystemMediaControls::setLoopStatus(LoopStatus status) {
|
||||
}
|
||||
|
||||
void SystemMediaControls::setShuffle(bool value) {
|
||||
}
|
||||
|
||||
void SystemMediaControls::setTitle(const QString &title) {
|
||||
const auto htitle = winrt::to_hstring(title.toStdString());
|
||||
WinRT::Try([&] { _private->displayProperties.Title(htitle); });
|
||||
}
|
||||
|
||||
void SystemMediaControls::setArtist(const QString &artist) {
|
||||
const auto hartist = winrt::to_hstring(artist.toStdString());
|
||||
WinRT::Try([&] { _private->displayProperties.Artist(hartist); });
|
||||
}
|
||||
|
||||
void SystemMediaControls::setThumbnail(const QImage &thumbnail) {
|
||||
auto thumbStream = winrt::Streams::InMemoryRandomAccessStream();
|
||||
_private->iconDataWriter = winrt::Streams::DataWriter(thumbStream);
|
||||
|
||||
const auto bitmapRawData = [&] {
|
||||
QByteArray bytes;
|
||||
QBuffer buffer(&bytes);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
thumbnail.save(&buffer, "JPG", 87);
|
||||
buffer.close();
|
||||
return std::vector<unsigned char>(bytes.begin(), bytes.end());
|
||||
}();
|
||||
|
||||
WinRT::Try([&] {
|
||||
_private->iconDataWriter.WriteBytes(bitmapRawData);
|
||||
|
||||
using namespace winrt::Windows;
|
||||
_private->iconDataWriter.StoreAsync().Completed([=,
|
||||
thumbStream = std::move(thumbStream)](
|
||||
Foundation::IAsyncOperation<uint32> asyncOperation,
|
||||
Foundation::AsyncStatus status) {
|
||||
|
||||
// Check the async operation completed successfully.
|
||||
if ((status != Foundation::AsyncStatus::Completed)
|
||||
|| FAILED(asyncOperation.ErrorCode())) {
|
||||
return;
|
||||
}
|
||||
|
||||
WinRT::Try([&] {
|
||||
_private->displayUpdater.Thumbnail(
|
||||
_private->referenceStatics.CreateFromStream(thumbStream));
|
||||
_private->displayUpdater.Update();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void SystemMediaControls::setDuration(int duration) {
|
||||
}
|
||||
|
||||
void SystemMediaControls::setPosition(int position) {
|
||||
}
|
||||
|
||||
void SystemMediaControls::setVolume(float64 volume) {
|
||||
}
|
||||
|
||||
void SystemMediaControls::clearThumbnail() {
|
||||
WinRT::Try([&] {
|
||||
_private->displayUpdater.Thumbnail(nullptr);
|
||||
_private->displayUpdater.Update();
|
||||
});
|
||||
}
|
||||
|
||||
void SystemMediaControls::clearMetadata() {
|
||||
WinRT::Try([&] {
|
||||
_private->displayUpdater.ClearAll();
|
||||
_private->controls.IsEnabled(false);
|
||||
});
|
||||
}
|
||||
|
||||
void SystemMediaControls::updateDisplay() {
|
||||
WinRT::Try([&] {
|
||||
_private->controls.IsEnabled(true);
|
||||
_private->displayUpdater.Type(winrt::Media::MediaPlaybackType::Music);
|
||||
_private->displayUpdater.Update();
|
||||
});
|
||||
}
|
||||
|
||||
auto SystemMediaControls::commandRequests() const
|
||||
-> rpl::producer<SystemMediaControls::Command> {
|
||||
return _private->commandRequests.events();
|
||||
}
|
||||
|
||||
rpl::producer<float64> SystemMediaControls::seekRequests() const {
|
||||
return rpl::never<float64>();
|
||||
}
|
||||
|
||||
rpl::producer<float64> SystemMediaControls::volumeChangeRequests() const {
|
||||
return rpl::never<float64>();
|
||||
}
|
||||
|
||||
rpl::producer<> SystemMediaControls::updatePositionRequests() const {
|
||||
return rpl::never<>();
|
||||
}
|
||||
|
||||
bool SystemMediaControls::seekingSupported() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SystemMediaControls::volumeSupported() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SystemMediaControls::Supported() {
|
||||
return ::Platform::IsWindows10OrGreater();
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
100
Telegram/lib_base/base/platform/win/base_system_unlock_win.cpp
Normal file
100
Telegram/lib_base/base/platform/win/base_system_unlock_win.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_system_unlock_win.h"
|
||||
|
||||
#include "base/platform/win/base_windows_winrt.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Security.Credentials.UI.h>
|
||||
#include <UserConsentVerifierInterop.h>
|
||||
|
||||
namespace base {
|
||||
namespace {
|
||||
|
||||
using namespace winrt::Windows::Security::Credentials::UI;
|
||||
|
||||
using AsyncStatus = winrt::Windows::Foundation::AsyncStatus;
|
||||
using winrt::Windows::Foundation::IAsyncOperation;
|
||||
|
||||
} // namespace
|
||||
|
||||
rpl::producer<SystemUnlockAvailability> SystemUnlockStatus(
|
||||
bool lookupDetails) {
|
||||
static auto result = rpl::variable<SystemUnlockAvailability>();
|
||||
WinRT::Try([&] {
|
||||
UserConsentVerifier::CheckAvailabilityAsync().Completed([](
|
||||
IAsyncOperation<UserConsentVerifierAvailability> that,
|
||||
AsyncStatus status) {
|
||||
const auto results = WinRT::Try([&] {
|
||||
return that.GetResults();
|
||||
});
|
||||
const auto available = (status == AsyncStatus::Completed)
|
||||
&& (results == UserConsentVerifierAvailability::Available);
|
||||
crl::on_main([=] {
|
||||
result = SystemUnlockAvailability{
|
||||
.known = true,
|
||||
.available = available,
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
return result.value();
|
||||
}
|
||||
|
||||
void SuggestSystemUnlock(
|
||||
not_null<QWidget*> parent,
|
||||
const QString &text,
|
||||
Fn<void(SystemUnlockResult)> done) {
|
||||
const auto window = parent->window();
|
||||
window->createWinId();
|
||||
const auto handle = reinterpret_cast<HWND>(window->winId());
|
||||
if (!handle) {
|
||||
done(SystemUnlockResult::Cancelled);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto completed = [=](
|
||||
IAsyncOperation<UserConsentVerificationResult> that,
|
||||
AsyncStatus status) -> void {
|
||||
const auto results = WinRT::Try([&] {
|
||||
return that.GetResults();
|
||||
});
|
||||
done((status != AsyncStatus::Completed)
|
||||
? SystemUnlockResult::Cancelled
|
||||
: (results == UserConsentVerificationResult::Verified)
|
||||
? SystemUnlockResult::Success
|
||||
: (results == UserConsentVerificationResult::RetriesExhausted)
|
||||
? SystemUnlockResult::FloodError
|
||||
: SystemUnlockResult::Cancelled);
|
||||
};
|
||||
const auto success = WinRT::Try([&] {
|
||||
const auto interop = winrt::get_activation_factory<
|
||||
UserConsentVerifier,
|
||||
IUserConsentVerifierInterop>();
|
||||
if (!interop) {
|
||||
done(SystemUnlockResult::Cancelled);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto wtext = text.toStdString();
|
||||
const auto htext = winrt::to_hstring(wtext);
|
||||
winrt::capture<IAsyncOperation<UserConsentVerificationResult>>(
|
||||
interop,
|
||||
&IUserConsentVerifierInterop::RequestVerificationForWindowAsync,
|
||||
handle,
|
||||
reinterpret_cast<HSTRING>(winrt::get_abi(htext))
|
||||
).Completed(completed);
|
||||
});
|
||||
if (!success) {
|
||||
done(SystemUnlockResult::Cancelled);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/system_unlock.h"
|
||||
207
Telegram/lib_base/base/platform/win/base_url_scheme_win.cpp
Normal file
207
Telegram/lib_base/base/platform/win/base_url_scheme_win.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_url_scheme_win.h"
|
||||
|
||||
#include <QtCore/QDir>
|
||||
|
||||
#include <windows.h>
|
||||
#include <array>
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
enum class Mode {
|
||||
Check,
|
||||
Write,
|
||||
};
|
||||
|
||||
bool OpenRegKey(Mode mode, const QString &key, PHKEY rkey) {
|
||||
const auto wkey = key.toStdWString();
|
||||
const auto opened = RegOpenKeyEx(
|
||||
HKEY_CURRENT_USER,
|
||||
wkey.c_str(),
|
||||
0,
|
||||
KEY_QUERY_VALUE | KEY_WRITE,
|
||||
rkey);
|
||||
if (opened == ERROR_SUCCESS) {
|
||||
return true;
|
||||
} else if (mode != Mode::Write) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto created = RegCreateKeyEx(
|
||||
HKEY_CURRENT_USER,
|
||||
wkey.c_str(),
|
||||
0,
|
||||
nullptr,
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_QUERY_VALUE | KEY_WRITE,
|
||||
nullptr,
|
||||
rkey,
|
||||
nullptr);
|
||||
if (created == ERROR_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemoveRegKey(const QString &key) {
|
||||
const auto wkey = key.toStdWString();
|
||||
return (RegDeleteKey(HKEY_CURRENT_USER, wkey.c_str()) == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool SetKeyValue(Mode mode, HKEY rkey, const QString &name, QString value) {
|
||||
static_assert(sizeof(WCHAR) == 2);
|
||||
static_assert(sizeof(wchar_t) == 2);
|
||||
|
||||
constexpr auto kBufferSize = 4096;
|
||||
constexpr auto kBufferByteSize = kBufferSize * 2;
|
||||
auto defaultType = DWORD();
|
||||
auto defaultByteSize = DWORD(kBufferByteSize);
|
||||
auto defaultByteValue = std::array<BYTE, kBufferByteSize>{ 0 };
|
||||
const auto wname = name.toStdWString();
|
||||
const auto queried = RegQueryValueEx(
|
||||
rkey,
|
||||
wname.c_str(),
|
||||
nullptr,
|
||||
&defaultType,
|
||||
defaultByteValue.data(),
|
||||
&defaultByteSize);
|
||||
auto defaultValue = std::array<WCHAR, kBufferSize>{ 0 };
|
||||
memcpy(defaultValue.data(), defaultByteValue.data(), kBufferByteSize);
|
||||
if ((queried == ERROR_SUCCESS)
|
||||
&& (defaultType == REG_SZ)
|
||||
&& (defaultByteSize == (value.size() + 1) * 2)
|
||||
&& (QString::fromWCharArray(
|
||||
defaultValue.data(),
|
||||
value.size()) == value)) {
|
||||
return true;
|
||||
} else if (mode != Mode::Write) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto wvalue = value.toStdWString();
|
||||
auto byteValue = std::vector<BYTE>((wvalue.size() + 1) * 2, 0);
|
||||
memcpy(byteValue.data(), wvalue.data(), wvalue.size() * 2);
|
||||
const auto written = RegSetValueEx(
|
||||
rkey,
|
||||
wname.c_str(),
|
||||
0,
|
||||
REG_SZ,
|
||||
byteValue.data(),
|
||||
byteValue.size());
|
||||
if (written == ERROR_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemoveKeyValue(HKEY rkey, const QString &name) {
|
||||
const auto wname = name.toStdWString();
|
||||
return (RegDeleteValue(rkey, wname.c_str()) == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool RegisterLegacy(Mode mode, const UrlSchemeDescriptor &d) {
|
||||
auto rkey = HKEY();
|
||||
const auto exe = QDir::toNativeSeparators(d.executable);
|
||||
const auto keyBase = "Software\\Classes\\" + d.protocol;
|
||||
const auto command = '"' + exe + "\" " + d.arguments + " -- \"%1\"";
|
||||
|
||||
return OpenRegKey(mode, keyBase, &rkey)
|
||||
&& SetKeyValue(mode, rkey, "URL Protocol", QString())
|
||||
&& SetKeyValue(mode, rkey, nullptr, "URL:" + d.protocolName)
|
||||
&& OpenRegKey(mode, keyBase + "\\DefaultIcon", &rkey)
|
||||
&& SetKeyValue(mode, rkey, nullptr, '"' + exe + ",1\"")
|
||||
&& OpenRegKey(mode, keyBase + "\\shell", &rkey)
|
||||
&& OpenRegKey(mode, keyBase + "\\shell\\open", &rkey)
|
||||
&& OpenRegKey(mode, keyBase + "\\shell\\open\\command", &rkey)
|
||||
&& SetKeyValue(mode, rkey, nullptr, command);
|
||||
}
|
||||
|
||||
void UnregisterLegacy(const UrlSchemeDescriptor &d) {
|
||||
const auto keyBase = "Software\\Classes\\" + d.protocol;
|
||||
RemoveRegKey(keyBase + "\\shell\\open\\command");
|
||||
RemoveRegKey(keyBase + "\\shell\\open");
|
||||
RemoveRegKey(keyBase + "\\shell");
|
||||
RemoveRegKey(keyBase + "\\DefaultIcon");
|
||||
RemoveRegKey(keyBase);
|
||||
}
|
||||
|
||||
bool RegisterDefaultProgram(Mode mode, const UrlSchemeDescriptor &d) {
|
||||
auto rkey = HKEY();
|
||||
const auto exe = QDir::toNativeSeparators(d.executable);
|
||||
const auto namedProtocol = d.shortAppName + '.' + d.protocol;
|
||||
const auto namedBase = "Software\\Classes\\" + namedProtocol;
|
||||
const auto longNamedBase = "Software\\" + d.longAppName;
|
||||
const auto registered = "SOFTWARE\\" + d.longAppName + "\\Capabilities";
|
||||
const auto command = '"' + exe + "\" " + d.arguments + " -- \"%1\"";
|
||||
|
||||
return OpenRegKey(mode, namedBase, &rkey)
|
||||
&& OpenRegKey(mode, namedBase + "\\DefaultIcon", &rkey)
|
||||
&& SetKeyValue(mode, rkey, nullptr, '"' + exe + ",1\"")
|
||||
&& OpenRegKey(mode, namedBase + "\\shell", &rkey)
|
||||
&& OpenRegKey(mode, namedBase + "\\shell\\open", &rkey)
|
||||
&& OpenRegKey(mode, namedBase + "\\shell\\open\\command", &rkey)
|
||||
&& SetKeyValue(mode, rkey, nullptr, command)
|
||||
&& OpenRegKey(mode, longNamedBase, &rkey)
|
||||
&& OpenRegKey(mode, longNamedBase + "\\Capabilities", &rkey)
|
||||
&& SetKeyValue(mode, rkey, "ApplicationName", d.displayAppName)
|
||||
&& SetKeyValue(
|
||||
mode,
|
||||
rkey,
|
||||
"ApplicationDescription",
|
||||
d.displayAppDescription)
|
||||
&& OpenRegKey(
|
||||
mode,
|
||||
longNamedBase + "\\Capabilities\\UrlAssociations",
|
||||
&rkey)
|
||||
&& SetKeyValue(mode, rkey, d.protocol, namedProtocol)
|
||||
&& OpenRegKey(mode, "Software\\RegisteredApplications", &rkey)
|
||||
&& SetKeyValue(mode, rkey, d.displayAppName, registered);
|
||||
}
|
||||
|
||||
void UnregisterDefaultProgram(const UrlSchemeDescriptor &d) {
|
||||
auto rkey = HKEY();
|
||||
const auto namedProtocol = d.shortAppName + '.' + d.protocol;
|
||||
const auto namedBase = "Software\\Classes\\" + namedProtocol;
|
||||
const auto longNamedBase = "Software\\" + d.longAppName;
|
||||
if (OpenRegKey(Mode::Check, "Software\\RegisteredApplications", &rkey)) {
|
||||
RemoveKeyValue(rkey, d.displayAppName);
|
||||
}
|
||||
RemoveRegKey(longNamedBase + "\\Capabilities\\UrlAssociations");
|
||||
RemoveRegKey(longNamedBase + "\\Capabilities");
|
||||
RemoveRegKey(longNamedBase);
|
||||
RemoveRegKey(namedBase + "\\shell\\open\\command");
|
||||
RemoveRegKey(namedBase + "\\shell\\open");
|
||||
RemoveRegKey(namedBase + "\\shell");
|
||||
RemoveRegKey(namedBase + "\\DefaultIcon");
|
||||
RemoveRegKey(namedBase);
|
||||
}
|
||||
|
||||
bool FullRegister(Mode mode, const UrlSchemeDescriptor &descriptor) {
|
||||
return RegisterDefaultProgram(mode, descriptor)
|
||||
&& RegisterLegacy(mode, descriptor);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CheckUrlScheme(const UrlSchemeDescriptor &descriptor) {
|
||||
return FullRegister(Mode::Check, descriptor);
|
||||
}
|
||||
|
||||
void RegisterUrlScheme(const UrlSchemeDescriptor &descriptor) {
|
||||
FullRegister(Mode::Write, descriptor);
|
||||
}
|
||||
|
||||
void UnregisterUrlScheme(const UrlSchemeDescriptor &descriptor) {
|
||||
if (CheckUrlScheme(descriptor)) {
|
||||
UnregisterDefaultProgram(descriptor);
|
||||
UnregisterLegacy(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/base_platform_url_scheme.h"
|
||||
137
Telegram/lib_base/base/platform/win/base_windows_co_task_mem.h
Normal file
137
Telegram/lib_base/base/platform/win/base_windows_co_task_mem.h
Normal file
@@ -0,0 +1,137 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <combaseapi.h>
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Item>
|
||||
struct FreePolicyNullTerminated {
|
||||
void destroy(Item *data) {
|
||||
}
|
||||
|
||||
struct Sentinel {
|
||||
friend inline bool operator==(Item *data, Sentinel) {
|
||||
return !*data;
|
||||
}
|
||||
friend inline bool operator!=(Item *data, Sentinel) {
|
||||
return !!*data;
|
||||
}
|
||||
};
|
||||
[[nodiscard]] Sentinel sentinel(const Item *data) const {
|
||||
return Sentinel();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Item>
|
||||
struct FreePolicyCounted {
|
||||
void destroy(Item *data) {
|
||||
if (data) {
|
||||
for (auto i = 0; i != count; ++i) {
|
||||
data[i].~Item();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] Item *sentinel(Item *data) const {
|
||||
return data + count;
|
||||
}
|
||||
[[nodiscard]] const Item *sentinel(const Item *data) const {
|
||||
return data + count;
|
||||
}
|
||||
|
||||
UINT32 count = 0;
|
||||
};
|
||||
|
||||
template <typename, template <typename...> class>
|
||||
struct instance_of_t : std::false_type {
|
||||
};
|
||||
|
||||
template <template <typename...> class Template, typename ...Args>
|
||||
struct instance_of_t<Template<Args...>, Template> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename Type, template <typename...> class Template>
|
||||
inline constexpr bool instance_of_v = instance_of_t<Type, Template>::value;
|
||||
|
||||
template <typename Item, typename FreePolicy>
|
||||
class CoTaskMemArray final : private FreePolicy {
|
||||
public:
|
||||
CoTaskMemArray() = default;
|
||||
~CoTaskMemArray() {
|
||||
if (_data) {
|
||||
FreePolicy::destroy(_data);
|
||||
CoTaskMemFree(_data);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] Item *data() const {
|
||||
return _data;
|
||||
}
|
||||
[[nodiscard]] bool valid() const {
|
||||
return (_data != nullptr);
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return _data != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] Item &operator[](int index) {
|
||||
return _data[index];
|
||||
}
|
||||
[[nodiscard]] const Item &operator[](int index) const {
|
||||
return _data[index];
|
||||
}
|
||||
|
||||
[[nodiscard]] Item *begin() {
|
||||
return _data;
|
||||
}
|
||||
[[nodiscard]] auto end() {
|
||||
return FreePolicy::sentinel(_data);
|
||||
}
|
||||
[[nodiscard]] const Item *begin() const {
|
||||
return _data;
|
||||
}
|
||||
[[nodiscard]] auto end() const {
|
||||
return FreePolicy::sentinel(_data);
|
||||
}
|
||||
[[nodiscard]] const Item *cbegin() const {
|
||||
return _data;
|
||||
}
|
||||
[[nodiscard]] auto cend() const {
|
||||
return FreePolicy::sentinel(_data);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto put() {
|
||||
if constexpr (instance_of_v<Item, CoTaskMemArray>) {
|
||||
static_assert(sizeof(*_data) == sizeof(void*));
|
||||
return reinterpret_cast<decltype(_data->put())*>(&_data);
|
||||
} else {
|
||||
return &_data;
|
||||
}
|
||||
}
|
||||
[[nodiscard]] UINT32 *put_size() {
|
||||
return &static_cast<FreePolicy*>(this)->count;
|
||||
}
|
||||
[[nodiscard]] int size() const {
|
||||
return int(static_cast<const FreePolicy*>(this)->count);
|
||||
}
|
||||
|
||||
private:
|
||||
Item *_data = nullptr;
|
||||
|
||||
};
|
||||
|
||||
using CoTaskMemString = CoTaskMemArray<
|
||||
WCHAR,
|
||||
FreePolicyNullTerminated<WCHAR>>;
|
||||
|
||||
using CoTaskMemStringArray = CoTaskMemArray<
|
||||
CoTaskMemString,
|
||||
FreePolicyCounted<CoTaskMemString>>;
|
||||
|
||||
} // namespace base
|
||||
25
Telegram/lib_base/base/platform/win/base_windows_gdiplus_h.h
Normal file
25
Telegram/lib_base/base/platform/win/base_windows_gdiplus_h.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <Unknwn.h>
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif // min
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif // max
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a, b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
#include <gdiplus.h>
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
14
Telegram/lib_base/base/platform/win/base_windows_rpcndr_h.h
Normal file
14
Telegram/lib_base/base/platform/win/base_windows_rpcndr_h.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <rpc.h>
|
||||
#include <rpcndr.h>
|
||||
|
||||
#ifdef small
|
||||
#undef small
|
||||
#endif // small
|
||||
@@ -0,0 +1,158 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_windows_safe_library.h"
|
||||
|
||||
#ifdef QT_VERSION
|
||||
#include "base/debug_log.h"
|
||||
#else
|
||||
#define LOG(...) (void)0
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
#define LOAD_SYMBOL(lib, name) ::base::Platform::LoadMethod(lib, #name, name)
|
||||
|
||||
namespace base {
|
||||
namespace Platform {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMaxPathLong = 32767;
|
||||
|
||||
__declspec(noreturn) void FatalError(
|
||||
const std::wstring &text,
|
||||
DWORD error = 0) {
|
||||
const auto lastError = error ? error : GetLastError();
|
||||
const auto full = lastError
|
||||
? (text + L"\n\nError Code: " + std::to_wstring(lastError))
|
||||
: text;
|
||||
MessageBox(nullptr, full.c_str(), L"Fatal Error", MB_ICONERROR);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
void CheckDynamicLibraries() {
|
||||
auto exePath = std::array<WCHAR, kMaxPathLong + 1>{ 0 };
|
||||
const auto exeLength = GetModuleFileName(
|
||||
nullptr,
|
||||
exePath.data(),
|
||||
kMaxPathLong + 1);
|
||||
if (!exeLength || exeLength >= kMaxPathLong + 1) {
|
||||
FatalError(L"Could not get executable path!");
|
||||
}
|
||||
const auto exe = std::wstring(exePath.data());
|
||||
const auto last1 = exe.find_last_of('\\');
|
||||
const auto last2 = exe.find_last_of('/');
|
||||
const auto last = std::max(
|
||||
(last1 == std::wstring::npos) ? -1 : int(last1),
|
||||
(last2 == std::wstring::npos) ? -1 : int(last2));
|
||||
if (last < 0) {
|
||||
FatalError(L"Could not get executable directory!");
|
||||
}
|
||||
const auto search = exe.substr(0, last + 1) + L"*.dll";
|
||||
|
||||
auto findData = WIN32_FIND_DATA();
|
||||
const auto findHandle = FindFirstFile(search.c_str(), &findData);
|
||||
if (findHandle == INVALID_HANDLE_VALUE) {
|
||||
const auto error = GetLastError();
|
||||
if (error == ERROR_FILE_NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
FatalError(L"Could not enumerate executable path!", error);
|
||||
}
|
||||
|
||||
do {
|
||||
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
continue;
|
||||
}
|
||||
const auto me = exe.substr(last + 1);
|
||||
FatalError(L"Unknown DLL library \"\
|
||||
" + std::wstring(findData.cFileName) + L"\" found \
|
||||
in the directory with " + me + L".\n\n\
|
||||
This may be a virus or a malicious program. \n\n\
|
||||
Please remove all DLL libraries from this directory:\n\n\
|
||||
" + exe.substr(0, last) + L"\n\n\
|
||||
Alternatively, you can move " + me + L" to a new directory.");
|
||||
} while (FindNextFile(findHandle, &findData));
|
||||
}
|
||||
|
||||
BOOL (__stdcall *SetDefaultDllDirectories)(_In_ DWORD DirectoryFlags);
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace details {
|
||||
|
||||
void *LoadMethodRaw(HINSTANCE library, LPCSTR name, WORD id) {
|
||||
const auto result = GetProcAddress(library, name);
|
||||
return result
|
||||
? result
|
||||
: id
|
||||
? GetProcAddress(library, MAKEINTRESOURCEA(id))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void ReportLoadFailure(HINSTANCE library, LPCSTR name, DWORD id) {
|
||||
constexpr auto kMaxPathLong = 32767;
|
||||
auto path = std::array<WCHAR, kMaxPathLong + 1>{ 0 };
|
||||
const auto length = GetModuleFileName(
|
||||
library,
|
||||
path.data(),
|
||||
kMaxPathLong);
|
||||
if (length > 0 && length < kMaxPathLong) {
|
||||
if (id) {
|
||||
LOG(("DLL Error: Failed to load '%1' from '%2' (ID: %3)."
|
||||
).arg(name
|
||||
).arg(QString::fromWCharArray(path.data())
|
||||
).arg(id));
|
||||
} else {
|
||||
LOG(("DLL Error: Failed to load '%1' from '%2'."
|
||||
).arg(name
|
||||
).arg(QString::fromWCharArray(path.data())));
|
||||
}
|
||||
} else {
|
||||
if (id) {
|
||||
LOG(("DLL Error: Failed to load '%1' from _unknown_ (ID: %2)."
|
||||
).arg(name
|
||||
).arg(id));
|
||||
} else {
|
||||
LOG(("DLL Error: Failed to load '%1' from _unknown_."
|
||||
).arg(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
void InitDynamicLibraries() {
|
||||
static const auto Inited = [] {
|
||||
const auto kernel = LoadLibrary(L"kernel32.dll");
|
||||
if (LOAD_SYMBOL(kernel, SetDefaultDllDirectories)) {
|
||||
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
} else {
|
||||
CheckDynamicLibraries();
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
}
|
||||
|
||||
HINSTANCE SafeLoadLibrary(LPCWSTR name, bool required) {
|
||||
InitDynamicLibraries();
|
||||
|
||||
if (const auto result = HINSTANCE(LoadLibrary(name))) {
|
||||
return result;
|
||||
} else if (required) {
|
||||
FatalError(L"Could not load required DLL '"
|
||||
+ std::wstring(name)
|
||||
+ L"'!");
|
||||
} else {
|
||||
LOG(("DLL Error: Could not load '%1'."
|
||||
).arg(QString::fromWCharArray(name)));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
} // namespace base
|
||||
@@ -0,0 +1,38 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// We try to keep this module free of external dependencies.
|
||||
|
||||
namespace base::Platform {
|
||||
namespace details {
|
||||
|
||||
[[nodiscard]] void *LoadMethodRaw(HINSTANCE library, LPCSTR name, WORD id);
|
||||
void ReportLoadFailure(HINSTANCE library, LPCSTR name, DWORD id);
|
||||
|
||||
} // namespace details
|
||||
|
||||
void InitDynamicLibraries();
|
||||
|
||||
HINSTANCE SafeLoadLibrary(LPCWSTR name, bool required = false);
|
||||
|
||||
template <typename Function>
|
||||
bool LoadMethod(HINSTANCE library, LPCSTR name, Function &f, WORD id = 0) {
|
||||
if (!library) {
|
||||
return false;
|
||||
} else if (const auto ptr = details::LoadMethodRaw(library, name, id)) {
|
||||
f = reinterpret_cast<Function>(ptr);
|
||||
return true;
|
||||
}
|
||||
f = nullptr;
|
||||
details::ReportLoadFailure(library, name, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
13
Telegram/lib_base/base/platform/win/base_windows_shlobj_h.h
Normal file
13
Telegram/lib_base/base/platform/win/base_windows_shlobj_h.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <shlobj.h>
|
||||
|
||||
#ifdef small
|
||||
#undef small
|
||||
#endif // small
|
||||
418
Telegram/lib_base/base/platform/win/base_windows_winrt.cpp
Normal file
418
Telegram/lib_base/base/platform/win/base_windows_winrt.cpp
Normal file
@@ -0,0 +1,418 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_windows_winrt.h"
|
||||
|
||||
#include "base/debug_log.h"
|
||||
#include "base/platform/win/base_windows_safe_library.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace base::WinRT {
|
||||
namespace {
|
||||
|
||||
int32_t(__stdcall *RoGetActivationFactory)(void* classId, winrt::guid const& iid, void** factory);
|
||||
int32_t(__stdcall *RoGetAgileReference)(uint32_t options, winrt::guid const& iid, void* object, void** reference);
|
||||
int32_t(__stdcall *SetThreadpoolTimerEx)(winrt::impl::ptp_timer, void*, uint32_t, uint32_t);
|
||||
int32_t(__stdcall *SetThreadpoolWaitEx)(winrt::impl::ptp_wait, void*, void*, void*);
|
||||
int32_t(__stdcall *RoOriginateLanguageException)(int32_t error, void* message, void* exception);
|
||||
int32_t(__stdcall *RoCaptureErrorContext)(int32_t error);
|
||||
void(__stdcall *RoFailFastWithErrorContext)(int32_t);
|
||||
int32_t(__stdcall *RoTransformError)(int32_t, int32_t, void*);
|
||||
void*(__stdcall *LoadLibraryExW)(wchar_t const* name, void* unused, uint32_t flags);
|
||||
int32_t(__stdcall *FreeLibrary)(void* library);
|
||||
void*(__stdcall *GetProcAddress)(void* library, char const* name);
|
||||
int32_t(__stdcall *SetErrorInfo)(uint32_t reserved, void* info);
|
||||
int32_t(__stdcall *GetErrorInfo)(uint32_t reserved, void** info);
|
||||
int32_t(__stdcall *CoInitializeEx)(void*, uint32_t type);
|
||||
void(__stdcall *CoUninitialize)();
|
||||
int32_t(__stdcall *CoCreateFreeThreadedMarshaler)(void* outer, void** marshaler);
|
||||
int32_t(__stdcall *CoCreateInstance)(winrt::guid const& clsid, void* outer, uint32_t context, winrt::guid const& iid, void** object);
|
||||
int32_t(__stdcall *CoGetCallContext)(winrt::guid const& iid, void** object);
|
||||
int32_t(__stdcall *CoGetObjectContext)(winrt::guid const& iid, void** object);
|
||||
int32_t(__stdcall *CoGetApartmentType)(int32_t* type, int32_t* qualifier);
|
||||
void*(__stdcall *CoTaskMemAlloc)(std::size_t size);
|
||||
void(__stdcall *CoTaskMemFree)(void* ptr);
|
||||
winrt::impl::bstr(__stdcall *SysAllocString)(wchar_t const* value);
|
||||
void(__stdcall *SysFreeString)(winrt::impl::bstr string);
|
||||
uint32_t(__stdcall *SysStringLen)(winrt::impl::bstr string);
|
||||
int32_t(__stdcall *IIDFromString)(wchar_t const* string, winrt::guid* iid);
|
||||
int32_t(__stdcall *MultiByteToWideChar)(uint32_t codepage, uint32_t flags, char const* in_string, int32_t in_size, wchar_t* out_string, int32_t out_size);
|
||||
int32_t(__stdcall *WideCharToMultiByte)(uint32_t codepage, uint32_t flags, wchar_t const* int_string, int32_t in_size, char* out_string, int32_t out_size, char const* default_char, int32_t* default_used);
|
||||
void*(__stdcall *HeapAlloc)(void* heap, uint32_t flags, size_t bytes);
|
||||
int32_t(__stdcall *HeapFree)(void* heap, uint32_t flags, void* value);
|
||||
void*(__stdcall *GetProcessHeap)();
|
||||
uint32_t(__stdcall *FormatMessageW)(uint32_t flags, void const* source, uint32_t code, uint32_t language, wchar_t* buffer, uint32_t size, va_list* arguments);
|
||||
uint32_t(__stdcall *GetLastError)();
|
||||
void(__stdcall *GetSystemTimePreciseAsFileTime)(void* result);
|
||||
uintptr_t(__stdcall *VirtualQuery)(void* address, void* buffer, uintptr_t length);
|
||||
void*(__stdcall *EncodePointer)(void* ptr);
|
||||
int32_t(__stdcall *OpenProcessToken)(void* process, uint32_t access, void** token);
|
||||
void*(__stdcall *GetCurrentProcess)();
|
||||
int32_t(__stdcall *DuplicateToken)(void* existing, uint32_t level, void** duplicate);
|
||||
int32_t(__stdcall *OpenThreadToken)(void* thread, uint32_t access, int32_t self, void** token);
|
||||
void*(__stdcall *GetCurrentThread)();
|
||||
int32_t(__stdcall *SetThreadToken)(void** thread, void* token);
|
||||
void(__stdcall *AcquireSRWLockExclusive)(winrt::impl::srwlock* lock);
|
||||
void(__stdcall *AcquireSRWLockShared)(winrt::impl::srwlock* lock);
|
||||
uint8_t(__stdcall *TryAcquireSRWLockExclusive)(winrt::impl::srwlock* lock);
|
||||
uint8_t(__stdcall *TryAcquireSRWLockShared)(winrt::impl::srwlock* lock);
|
||||
void(__stdcall *ReleaseSRWLockExclusive)(winrt::impl::srwlock* lock);
|
||||
void(__stdcall *ReleaseSRWLockShared)(winrt::impl::srwlock* lock);
|
||||
int32_t(__stdcall *SleepConditionVariableSRW)(winrt::impl::condition_variable* cv, winrt::impl::srwlock* lock, uint32_t milliseconds, uint32_t flags);
|
||||
void(__stdcall *WakeConditionVariable)(winrt::impl::condition_variable* cv);
|
||||
void(__stdcall *WakeAllConditionVariable)(winrt::impl::condition_variable* cv);
|
||||
void*(__stdcall *InterlockedPushEntrySList)(void* head, void* entry);
|
||||
void*(__stdcall *InterlockedFlushSList)(void* head);
|
||||
void*(__stdcall *CreateEventW)(void*, int32_t, int32_t, void*);
|
||||
int32_t(__stdcall *SetEvent)(void*);
|
||||
int32_t(__stdcall *CloseHandle)(void* hObject);
|
||||
uint32_t(__stdcall *WaitForSingleObject)(void* handle, uint32_t milliseconds);
|
||||
int32_t(__stdcall *TrySubmitThreadpoolCallback)(void(__stdcall *callback)(void*, void* context), void* context, void*);
|
||||
winrt::impl::ptp_timer(__stdcall *CreateThreadpoolTimer)(void(__stdcall *callback)(void*, void* context, void*), void* context, void*);
|
||||
void(__stdcall *SetThreadpoolTimer)(winrt::impl::ptp_timer timer, void* time, uint32_t period, uint32_t window);
|
||||
void(__stdcall *CloseThreadpoolTimer)(winrt::impl::ptp_timer timer);
|
||||
winrt::impl::ptp_wait(__stdcall *CreateThreadpoolWait)(void(__stdcall *callback)(void*, void* context, void*, uint32_t result), void* context, void*);
|
||||
void(__stdcall *SetThreadpoolWait)(winrt::impl::ptp_wait wait, void* handle, void* timeout);
|
||||
void(__stdcall *CloseThreadpoolWait)(winrt::impl::ptp_wait wait);
|
||||
winrt::impl::ptp_io(__stdcall *CreateThreadpoolIo)(void* object, void(__stdcall *callback)(void*, void* context, void* overlapped, uint32_t result, std::size_t bytes, void*) noexcept, void* context, void*);
|
||||
void(__stdcall *StartThreadpoolIo)(winrt::impl::ptp_io io);
|
||||
void(__stdcall *CancelThreadpoolIo)(winrt::impl::ptp_io io);
|
||||
void(__stdcall *CloseThreadpoolIo)(winrt::impl::ptp_io io);
|
||||
winrt::impl::ptp_pool(__stdcall *CreateThreadpool)(void* reserved);
|
||||
void(__stdcall *SetThreadpoolThreadMaximum)(winrt::impl::ptp_pool pool, uint32_t value);
|
||||
int32_t(__stdcall *SetThreadpoolThreadMinimum)(winrt::impl::ptp_pool pool, uint32_t value);
|
||||
void(__stdcall *CloseThreadpool)(winrt::impl::ptp_pool pool);
|
||||
|
||||
[[nodiscard]] bool Resolve() {
|
||||
const auto ole32 = Platform::SafeLoadLibrary(L"ole32.dll");
|
||||
const auto oleaut32 = Platform::SafeLoadLibrary(L"oleaut32.dll");
|
||||
const auto combase = Platform::SafeLoadLibrary(L"combase.dll");
|
||||
const auto kernel32 = Platform::SafeLoadLibrary(L"kernel32.dll");
|
||||
const auto advapi32 = Platform::SafeLoadLibrary(L"advapi32.dll");
|
||||
auto total = 0, resolved = 0;
|
||||
#define LOAD_SYMBOL(lib, name) ++total; if (Platform::LoadMethod(lib, #name, name)) ++resolved;
|
||||
LOAD_SYMBOL(combase, RoGetActivationFactory);
|
||||
LOAD_SYMBOL(combase, RoGetAgileReference);
|
||||
LOAD_SYMBOL(kernel32, SetThreadpoolTimerEx);
|
||||
LOAD_SYMBOL(kernel32, SetThreadpoolWaitEx);
|
||||
LOAD_SYMBOL(combase, RoOriginateLanguageException);
|
||||
LOAD_SYMBOL(combase, RoCaptureErrorContext);
|
||||
LOAD_SYMBOL(combase, RoFailFastWithErrorContext);
|
||||
LOAD_SYMBOL(combase, RoTransformError);
|
||||
LOAD_SYMBOL(kernel32, LoadLibraryExW);
|
||||
LOAD_SYMBOL(kernel32, FreeLibrary);
|
||||
LOAD_SYMBOL(kernel32, GetProcAddress);
|
||||
LOAD_SYMBOL(oleaut32, SetErrorInfo);
|
||||
LOAD_SYMBOL(oleaut32, GetErrorInfo);
|
||||
LOAD_SYMBOL(ole32, CoInitializeEx);
|
||||
LOAD_SYMBOL(ole32, CoUninitialize);
|
||||
LOAD_SYMBOL(ole32, CoCreateFreeThreadedMarshaler);
|
||||
LOAD_SYMBOL(ole32, CoCreateInstance);
|
||||
LOAD_SYMBOL(ole32, CoGetCallContext);
|
||||
LOAD_SYMBOL(ole32, CoGetObjectContext);
|
||||
LOAD_SYMBOL(ole32, CoGetApartmentType);
|
||||
LOAD_SYMBOL(ole32, CoTaskMemAlloc);
|
||||
LOAD_SYMBOL(ole32, CoTaskMemFree);
|
||||
LOAD_SYMBOL(oleaut32, SysAllocString);
|
||||
LOAD_SYMBOL(oleaut32, SysFreeString);
|
||||
LOAD_SYMBOL(oleaut32, SysStringLen);
|
||||
LOAD_SYMBOL(ole32, IIDFromString);
|
||||
LOAD_SYMBOL(kernel32, MultiByteToWideChar);
|
||||
LOAD_SYMBOL(kernel32, WideCharToMultiByte);
|
||||
LOAD_SYMBOL(kernel32, HeapAlloc);
|
||||
LOAD_SYMBOL(kernel32, HeapFree);
|
||||
LOAD_SYMBOL(kernel32, GetProcessHeap);
|
||||
LOAD_SYMBOL(kernel32, FormatMessageW);
|
||||
LOAD_SYMBOL(kernel32, GetLastError);
|
||||
LOAD_SYMBOL(kernel32, GetSystemTimePreciseAsFileTime);
|
||||
LOAD_SYMBOL(kernel32, VirtualQuery);
|
||||
LOAD_SYMBOL(kernel32, EncodePointer);
|
||||
LOAD_SYMBOL(kernel32, OpenProcessToken);
|
||||
LOAD_SYMBOL(kernel32, GetCurrentProcess);
|
||||
LOAD_SYMBOL(advapi32, DuplicateToken);
|
||||
LOAD_SYMBOL(advapi32, OpenThreadToken);
|
||||
LOAD_SYMBOL(kernel32, GetCurrentThread);
|
||||
LOAD_SYMBOL(kernel32, SetThreadToken);
|
||||
LOAD_SYMBOL(kernel32, AcquireSRWLockExclusive);
|
||||
LOAD_SYMBOL(kernel32, AcquireSRWLockShared);
|
||||
LOAD_SYMBOL(kernel32, TryAcquireSRWLockExclusive);
|
||||
LOAD_SYMBOL(kernel32, TryAcquireSRWLockShared);
|
||||
LOAD_SYMBOL(kernel32, ReleaseSRWLockExclusive);
|
||||
LOAD_SYMBOL(kernel32, ReleaseSRWLockShared);
|
||||
LOAD_SYMBOL(kernel32, SleepConditionVariableSRW);
|
||||
LOAD_SYMBOL(kernel32, WakeConditionVariable);
|
||||
LOAD_SYMBOL(kernel32, WakeAllConditionVariable);
|
||||
LOAD_SYMBOL(kernel32, InterlockedPushEntrySList);
|
||||
LOAD_SYMBOL(kernel32, InterlockedFlushSList);
|
||||
LOAD_SYMBOL(kernel32, CreateEventW);
|
||||
LOAD_SYMBOL(kernel32, SetEvent);
|
||||
LOAD_SYMBOL(kernel32, CloseHandle);
|
||||
LOAD_SYMBOL(kernel32, WaitForSingleObject);
|
||||
LOAD_SYMBOL(kernel32, TrySubmitThreadpoolCallback);
|
||||
LOAD_SYMBOL(kernel32, CreateThreadpoolTimer);
|
||||
LOAD_SYMBOL(kernel32, SetThreadpoolTimer);
|
||||
LOAD_SYMBOL(kernel32, CloseThreadpoolTimer);
|
||||
LOAD_SYMBOL(kernel32, CreateThreadpoolWait);
|
||||
LOAD_SYMBOL(kernel32, SetThreadpoolWait);
|
||||
LOAD_SYMBOL(kernel32, CloseThreadpoolWait);
|
||||
LOAD_SYMBOL(kernel32, CreateThreadpoolIo);
|
||||
LOAD_SYMBOL(kernel32, StartThreadpoolIo);
|
||||
LOAD_SYMBOL(kernel32, CancelThreadpoolIo);
|
||||
LOAD_SYMBOL(kernel32, CloseThreadpoolIo);
|
||||
LOAD_SYMBOL(kernel32, CreateThreadpool);
|
||||
LOAD_SYMBOL(kernel32, SetThreadpoolThreadMaximum);
|
||||
LOAD_SYMBOL(kernel32, SetThreadpoolThreadMinimum);
|
||||
LOAD_SYMBOL(kernel32, CloseThreadpool);
|
||||
#undef LOAD_SYMBOL
|
||||
return (total == resolved);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
[[nodiscard]] bool Supported() {
|
||||
static const auto Result = Resolve();
|
||||
return Result;
|
||||
}
|
||||
|
||||
} // namespace base::WinRT
|
||||
|
||||
namespace P = base::WinRT;
|
||||
|
||||
extern "C" {
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept {
|
||||
return P::RoGetActivationFactory(classId, iid, factory);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_RoGetAgileReference(uint32_t options, winrt::guid const& iid, void* object, void** reference) noexcept {
|
||||
return P::RoGetAgileReference(options, iid, object, reference);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_SetThreadpoolTimerEx(winrt::impl::ptp_timer timer, void *time, uint32_t period, uint32_t window) noexcept {
|
||||
return P::SetThreadpoolTimerEx(timer, time, period, window);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_SetThreadpoolWaitEx(winrt::impl::ptp_wait wait, void *handle, void *timeout, void *reserved) noexcept {
|
||||
return P::SetThreadpoolWaitEx(wait, handle, timeout, reserved);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_RoOriginateLanguageException(int32_t error, void* message, void* exception) noexcept {
|
||||
return P::RoOriginateLanguageException
|
||||
? P::RoOriginateLanguageException(error, message, exception)
|
||||
: TRUE;
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_RoCaptureErrorContext(int32_t error) noexcept {
|
||||
return P::RoCaptureErrorContext(error);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_RoFailFastWithErrorContext(int32_t error) noexcept {
|
||||
return P::RoFailFastWithErrorContext(error);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_RoTransformError(int32_t error, int32_t transform, void *context) noexcept {
|
||||
return P::RoTransformError(error, transform, context);
|
||||
}
|
||||
|
||||
void* __stdcall WINRT_IMPL_LoadLibraryExW(wchar_t const* name, void* unused, uint32_t flags) noexcept {
|
||||
return P::LoadLibraryExW(name, unused, flags);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_FreeLibrary(void* library) noexcept {
|
||||
return P::FreeLibrary(library);
|
||||
}
|
||||
|
||||
void* __stdcall WINRT_IMPL_GetProcAddress(void* library, char const* name) noexcept {
|
||||
return P::GetProcAddress(library, name);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_SetErrorInfo(uint32_t reserved, void* info) noexcept {
|
||||
return P::SetErrorInfo(reserved, info);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_GetErrorInfo(uint32_t reserved, void** info) noexcept {
|
||||
return P::GetErrorInfo(reserved, info);
|
||||
}
|
||||
int32_t __stdcall WINRT_IMPL_CoInitializeEx(void *reserved, uint32_t type) noexcept {
|
||||
return P::CoInitializeEx(reserved, type);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept {
|
||||
return P::CoCreateFreeThreadedMarshaler(outer, marshaler);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_CoCreateInstance(winrt::guid const& clsid, void* outer, uint32_t context, winrt::guid const& iid, void** object) noexcept {
|
||||
return P::CoCreateInstance(clsid, outer, context, iid, object);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_CoGetCallContext(winrt::guid const& iid, void** object) noexcept {
|
||||
return P::CoGetCallContext(iid, object);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_CoGetApartmentType(int32_t* type, int32_t* qualifier) noexcept {
|
||||
return P::CoGetApartmentType(type, qualifier);
|
||||
}
|
||||
|
||||
void* __stdcall WINRT_IMPL_CoTaskMemAlloc(std::size_t size) noexcept {
|
||||
return P::CoTaskMemAlloc(size);
|
||||
}
|
||||
void __stdcall WINRT_IMPL_CoTaskMemFree(void* ptr) noexcept {
|
||||
return P::CoTaskMemFree(ptr);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_SysFreeString(winrt::impl::bstr string) noexcept {
|
||||
return P::SysFreeString(string);
|
||||
}
|
||||
|
||||
uint32_t __stdcall WINRT_IMPL_SysStringLen(winrt::impl::bstr string) noexcept {
|
||||
return P::SysStringLen(string);
|
||||
}
|
||||
int32_t __stdcall WINRT_IMPL_IIDFromString(wchar_t const* string, winrt::guid* iid) noexcept {
|
||||
return P::IIDFromString(string, iid);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_MultiByteToWideChar(uint32_t codepage, uint32_t flags, char const* in_string, int32_t in_size, wchar_t* out_string, int32_t out_size) noexcept {
|
||||
return P::MultiByteToWideChar(codepage, flags, in_string, in_size, out_string, out_size);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_WideCharToMultiByte(uint32_t codepage, uint32_t flags, wchar_t const* int_string, int32_t in_size, char* out_string, int32_t out_size, char const* default_char, int32_t* default_used) noexcept {
|
||||
return P::WideCharToMultiByte(codepage, flags, int_string, in_size, out_string, out_size, default_char, default_used);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_HeapFree(void* heap, uint32_t flags, void* value) noexcept {
|
||||
return P::HeapFree(heap, flags, value);
|
||||
}
|
||||
|
||||
void* __stdcall WINRT_IMPL_GetProcessHeap() noexcept {
|
||||
return P::GetProcessHeap();
|
||||
}
|
||||
|
||||
uint32_t __stdcall WINRT_IMPL_FormatMessageW(uint32_t flags, void const* source, uint32_t code, uint32_t language, wchar_t* buffer, uint32_t size, va_list* arguments) noexcept {
|
||||
return P::FormatMessageW(flags, source, code, language, buffer, size, arguments);
|
||||
}
|
||||
|
||||
uint32_t __stdcall WINRT_IMPL_GetLastError() noexcept {
|
||||
return P::GetLastError();
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_OpenProcessToken(void* process, uint32_t access, void** token) noexcept {
|
||||
return P::OpenProcessToken(process, access, token);
|
||||
}
|
||||
|
||||
void* __stdcall WINRT_IMPL_GetCurrentProcess() noexcept {
|
||||
return P::GetCurrentProcess();
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_DuplicateToken(void* existing, uint32_t level, void** duplicate) noexcept {
|
||||
return P::DuplicateToken(existing, level, duplicate);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_OpenThreadToken(void* thread, uint32_t access, int32_t self, void** token) noexcept {
|
||||
return P::OpenThreadToken(thread, access, self, token);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_AcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept {
|
||||
return P::AcquireSRWLockExclusive(lock);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_AcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept {
|
||||
return P::AcquireSRWLockShared(lock);
|
||||
}
|
||||
|
||||
uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept {
|
||||
return P::TryAcquireSRWLockExclusive(lock);
|
||||
}
|
||||
|
||||
uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept {
|
||||
return P::TryAcquireSRWLockShared(lock);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_ReleaseSRWLockExclusive(winrt::impl::srwlock* lock) noexcept {
|
||||
return P::ReleaseSRWLockExclusive(lock);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_ReleaseSRWLockShared(winrt::impl::srwlock* lock) noexcept {
|
||||
return P::ReleaseSRWLockShared(lock);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_WakeConditionVariable(winrt::impl::condition_variable* cv) noexcept {
|
||||
return P::WakeConditionVariable(cv);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_WakeAllConditionVariable(winrt::impl::condition_variable* cv) noexcept {
|
||||
return P::WakeAllConditionVariable(cv);
|
||||
}
|
||||
|
||||
void* __stdcall WINRT_IMPL_InterlockedPushEntrySList(void* head, void* entry) noexcept {
|
||||
return P::InterlockedPushEntrySList(head, entry);
|
||||
}
|
||||
|
||||
void* __stdcall WINRT_IMPL_CreateEventW(void *event, int32_t manual, int32_t initial, void *name) noexcept {
|
||||
return P::CreateEventW(event, manual, initial, name);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_SetEvent(void *event) noexcept {
|
||||
return P::SetEvent(event);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_CloseHandle(void* hObject) noexcept {
|
||||
return P::CloseHandle(hObject);
|
||||
}
|
||||
|
||||
uint32_t __stdcall WINRT_IMPL_WaitForSingleObject(void* handle, uint32_t milliseconds) noexcept {
|
||||
return P::WaitForSingleObject(handle, milliseconds);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_TrySubmitThreadpoolCallback(void(__stdcall *callback)(void*, void* context), void* context, void*) noexcept {
|
||||
return P::TrySubmitThreadpoolCallback(callback, context, context);
|
||||
}
|
||||
|
||||
winrt::impl::ptp_timer __stdcall WINRT_IMPL_CreateThreadpoolTimer(void(__stdcall *callback)(void*, void* context, void*), void* context, void*) noexcept {
|
||||
return P::CreateThreadpoolTimer(callback, context, context);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_SetThreadpoolTimer(winrt::impl::ptp_timer timer, void* time, uint32_t period, uint32_t window) noexcept {
|
||||
return P::SetThreadpoolTimer(timer, time, period, window);
|
||||
}
|
||||
|
||||
winrt::impl::ptp_wait __stdcall WINRT_IMPL_CreateThreadpoolWait(void(__stdcall *callback)(void*, void* context, void*, uint32_t result), void* context, void*) noexcept {
|
||||
return P::CreateThreadpoolWait(callback, context, context);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_SetThreadpoolWait(winrt::impl::ptp_wait wait, void* handle, void* timeout) noexcept {
|
||||
return P::SetThreadpoolWait(wait, handle, timeout);
|
||||
}
|
||||
|
||||
winrt::impl::ptp_io __stdcall WINRT_IMPL_CreateThreadpoolIo(void* object, void(__stdcall *callback)(void*, void* context, void* overlapped, uint32_t result, std::size_t bytes, void*) noexcept, void* context, void*) noexcept {
|
||||
return P::CreateThreadpoolIo(object, callback, context, context);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_StartThreadpoolIo(winrt::impl::ptp_io io) noexcept {
|
||||
return P::StartThreadpoolIo(io);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_CancelThreadpoolIo(winrt::impl::ptp_io io) noexcept {
|
||||
return P::CancelThreadpoolIo(io);
|
||||
}
|
||||
|
||||
winrt::impl::ptp_pool __stdcall WINRT_IMPL_CreateThreadpool(void* reserved) noexcept {
|
||||
return P::CreateThreadpool(reserved);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_SetThreadpoolThreadMaximum(winrt::impl::ptp_pool pool, uint32_t value) noexcept {
|
||||
return P::SetThreadpoolThreadMaximum(pool, value);
|
||||
}
|
||||
|
||||
int32_t __stdcall WINRT_IMPL_SetThreadpoolThreadMinimum(winrt::impl::ptp_pool pool, uint32_t value) noexcept {
|
||||
return P::SetThreadpoolThreadMinimum(pool, value);
|
||||
}
|
||||
|
||||
void __stdcall WINRT_IMPL_CloseThreadpool(winrt::impl::ptp_pool pool) noexcept {
|
||||
return P::CloseThreadpool(pool);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
78
Telegram/lib_base/base/platform/win/base_windows_winrt.h
Normal file
78
Telegram/lib_base/base/platform/win/base_windows_winrt.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/debug_log.h"
|
||||
|
||||
// winrt::guid defines a constructor from GUID only if knows IUnknown.
|
||||
#include <Unknwnbase.h>
|
||||
|
||||
// class has virtual functions, but destructor is not virtual
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4265)
|
||||
#include <winrt/base.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
namespace base::WinRT {
|
||||
namespace details {
|
||||
|
||||
template <typename Method>
|
||||
inline constexpr bool ReturnsVoid = std::is_same_v<
|
||||
std::invoke_result_t<Method>,
|
||||
void>;
|
||||
|
||||
template <typename Method>
|
||||
using TryResult = std::conditional_t<
|
||||
ReturnsVoid<Method>,
|
||||
bool,
|
||||
std::optional<std::invoke_result_t<Method>>>;
|
||||
|
||||
} // namespace details
|
||||
|
||||
[[nodiscard]] bool Supported();
|
||||
|
||||
template <typename Method>
|
||||
inline details::TryResult<Method> TryNoCheck(Method &&method) noexcept {
|
||||
try {
|
||||
if constexpr (details::ReturnsVoid<Method>) {
|
||||
method();
|
||||
return true;
|
||||
} else {
|
||||
return method();
|
||||
}
|
||||
} catch (const std::bad_alloc &) {
|
||||
Unexpected("Could not allocate in WinRT.");
|
||||
} catch (const winrt::hresult_error &error) {
|
||||
LOG(("WinRT Error: %1 (%2)"
|
||||
).arg(error.code()
|
||||
).arg(QString::fromWCharArray(error.message().c_str())));
|
||||
return {};
|
||||
} catch (...) {
|
||||
LOG(("WinRT Error: Unknown."));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Method>
|
||||
inline details::TryResult<Method> Try(Method &&method) noexcept {
|
||||
if (!Supported()) {
|
||||
return {};
|
||||
}
|
||||
return TryNoCheck(std::forward<Method>(method));
|
||||
}
|
||||
|
||||
template <typename Interface>
|
||||
auto TryCreateInstance(
|
||||
const winrt::guid &clsid,
|
||||
uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/,
|
||||
void *outer = nullptr) {
|
||||
return TryNoCheck([&] {
|
||||
return winrt::create_instance<Interface>(clsid, context, outer);
|
||||
}).value_or(winrt::com_ptr<Interface>());
|
||||
}
|
||||
|
||||
} // namespace base::WinRT
|
||||
238
Telegram/lib_base/base/platform/win/base_windows_wrl.cpp
Normal file
238
Telegram/lib_base/base/platform/win/base_windows_wrl.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#include "base/platform/win/base_windows_wrl.h"
|
||||
|
||||
#include "base/platform/win/base_windows_safe_library.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
|
||||
#define LOAD_SYMBOL(lib, name) ::base::Platform::LoadMethod(lib, #name, name)
|
||||
|
||||
namespace base::Platform {
|
||||
namespace {
|
||||
|
||||
using namespace ::Platform;
|
||||
|
||||
HRESULT(__stdcall *RoGetActivationFactory)(
|
||||
_In_ HSTRING activatableClassId,
|
||||
_In_ REFIID iid,
|
||||
_COM_Outptr_ void ** factory);
|
||||
|
||||
HRESULT(__stdcall *RoActivateInstance)(
|
||||
_In_ HSTRING activatableClassId,
|
||||
_COM_Outptr_ IInspectable** instance);
|
||||
|
||||
HRESULT(__stdcall *RoRegisterActivationFactories)(
|
||||
_In_reads_(count) HSTRING* activatableClassIds,
|
||||
_In_reads_(count) PFNGETACTIVATIONFACTORY* activationFactoryCallbacks,
|
||||
_In_ UINT32 count,
|
||||
_Out_ RO_REGISTRATION_COOKIE* cookie);
|
||||
|
||||
void(__stdcall *RoRevokeActivationFactories)(
|
||||
_In_ RO_REGISTRATION_COOKIE cookie);
|
||||
|
||||
HRESULT(__stdcall *WindowsCreateString)(
|
||||
_In_reads_opt_(length) PCNZWCH sourceString,
|
||||
UINT32 length,
|
||||
_Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING* string);
|
||||
|
||||
HRESULT(__stdcall *WindowsCreateStringReference)(
|
||||
_In_reads_opt_(length + 1) PCWSTR sourceString,
|
||||
UINT32 length,
|
||||
_Out_ HSTRING_HEADER * hstringHeader,
|
||||
_Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING *string);
|
||||
|
||||
HRESULT(__stdcall *WindowsDeleteString)(
|
||||
_In_opt_ HSTRING string);
|
||||
|
||||
PCWSTR(__stdcall *WindowsGetStringRawBuffer)(
|
||||
_In_opt_ HSTRING string,
|
||||
_Out_opt_ UINT32* length);
|
||||
|
||||
BOOL(__stdcall *WindowsIsStringEmpty)(
|
||||
_In_opt_ HSTRING string);
|
||||
|
||||
HRESULT(__stdcall *WindowsStringHasEmbeddedNull)(
|
||||
_In_opt_ HSTRING string,
|
||||
_Out_ BOOL* hasEmbedNull);
|
||||
|
||||
BOOL(__stdcall *RoOriginateErrorW)(
|
||||
_In_ HRESULT error,
|
||||
_In_ UINT cchMax,
|
||||
_When_(cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS))
|
||||
_When_(cchMax > 0 && cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(cchMax))
|
||||
_When_(cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS)) PCWSTR message);
|
||||
|
||||
BOOL(__stdcall *RoOriginateError)(
|
||||
_In_ HRESULT error,
|
||||
_In_opt_ HSTRING message);
|
||||
|
||||
} // namespace
|
||||
|
||||
bool SupportsWRL() {
|
||||
struct State {
|
||||
bool inited = false;
|
||||
bool supported = false;
|
||||
};
|
||||
static auto state = State();
|
||||
if (state.inited) {
|
||||
return state.supported;
|
||||
}
|
||||
state.inited = true;
|
||||
if (IsWindows8OrGreater()) {
|
||||
const auto combase = SafeLoadLibrary(L"combase.dll");
|
||||
state.supported = combase
|
||||
&& LOAD_SYMBOL(combase, RoGetActivationFactory)
|
||||
&& LOAD_SYMBOL(combase, RoActivateInstance)
|
||||
&& LOAD_SYMBOL(combase, RoRegisterActivationFactories)
|
||||
&& LOAD_SYMBOL(combase, RoRevokeActivationFactories)
|
||||
&& LOAD_SYMBOL(combase, WindowsCreateString)
|
||||
&& LOAD_SYMBOL(combase, WindowsCreateStringReference)
|
||||
&& LOAD_SYMBOL(combase, WindowsDeleteString)
|
||||
&& LOAD_SYMBOL(combase, WindowsGetStringRawBuffer)
|
||||
&& LOAD_SYMBOL(combase, WindowsIsStringEmpty)
|
||||
&& LOAD_SYMBOL(combase, WindowsStringHasEmbeddedNull);
|
||||
}
|
||||
return state.supported;
|
||||
}
|
||||
|
||||
} // namespace base::Platform
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
|
||||
namespace P = base::Platform;
|
||||
|
||||
extern "C" {
|
||||
|
||||
_Check_return_ HRESULT WINAPI RoActivateInstance(
|
||||
_In_ HSTRING activatableClassId,
|
||||
_COM_Outptr_ IInspectable** instance
|
||||
) {
|
||||
return P::SupportsWRL()
|
||||
? P::RoActivateInstance(activatableClassId, instance)
|
||||
: CO_E_DLLNOTFOUND;
|
||||
}
|
||||
|
||||
_Check_return_ HRESULT WINAPI RoGetActivationFactory(
|
||||
_In_ HSTRING activatableClassId,
|
||||
_In_ REFIID iid,
|
||||
_COM_Outptr_ void** factory
|
||||
) {
|
||||
return P::SupportsWRL()
|
||||
? P::RoGetActivationFactory(activatableClassId, iid, factory)
|
||||
: CO_E_DLLNOTFOUND;
|
||||
}
|
||||
|
||||
_Check_return_ HRESULT WINAPI RoRegisterActivationFactories(
|
||||
_In_reads_(count) HSTRING* activatableClassIds,
|
||||
_In_reads_(count) PFNGETACTIVATIONFACTORY* activationFactoryCallbacks,
|
||||
_In_ UINT32 count,
|
||||
_Out_ RO_REGISTRATION_COOKIE* cookie
|
||||
) {
|
||||
return P::SupportsWRL()
|
||||
? P::RoRegisterActivationFactories(
|
||||
activatableClassIds,
|
||||
activationFactoryCallbacks,
|
||||
count,
|
||||
cookie)
|
||||
: CO_E_DLLNOTFOUND;
|
||||
}
|
||||
|
||||
void
|
||||
WINAPI
|
||||
RoRevokeActivationFactories(
|
||||
_In_ RO_REGISTRATION_COOKIE cookie
|
||||
) {
|
||||
if (P::SupportsWRL()) {
|
||||
P::RoRevokeActivationFactories(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
STDAPI
|
||||
WindowsCreateString(
|
||||
_In_reads_opt_(length) PCNZWCH sourceString,
|
||||
UINT32 length,
|
||||
_Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING* string
|
||||
) {
|
||||
return P::SupportsWRL()
|
||||
? P::WindowsCreateString(sourceString, length, string)
|
||||
: CO_E_DLLNOTFOUND;
|
||||
}
|
||||
|
||||
STDAPI
|
||||
WindowsCreateStringReference(
|
||||
_In_reads_opt_(length + 1) PCWSTR sourceString,
|
||||
UINT32 length,
|
||||
_Out_ HSTRING_HEADER* hstringHeader,
|
||||
_Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING* string
|
||||
) {
|
||||
return P::SupportsWRL()
|
||||
? P::WindowsCreateStringReference(
|
||||
sourceString,
|
||||
length,
|
||||
hstringHeader,
|
||||
string)
|
||||
: CO_E_DLLNOTFOUND;
|
||||
}
|
||||
|
||||
STDAPI
|
||||
WindowsDeleteString(
|
||||
_In_opt_ HSTRING string
|
||||
) {
|
||||
return P::SupportsWRL()
|
||||
? P::WindowsDeleteString(string)
|
||||
: CO_E_DLLNOTFOUND;
|
||||
}
|
||||
|
||||
STDAPI_(PCWSTR)
|
||||
WindowsGetStringRawBuffer(
|
||||
_In_opt_ HSTRING string,
|
||||
_Out_opt_ UINT32* length) {
|
||||
return P::SupportsWRL()
|
||||
? P::WindowsGetStringRawBuffer(string, length)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
STDAPI_(BOOL)
|
||||
WindowsIsStringEmpty(
|
||||
_In_opt_ HSTRING string
|
||||
) {
|
||||
return P::SupportsWRL() && P::WindowsIsStringEmpty(string);
|
||||
}
|
||||
|
||||
STDAPI
|
||||
WindowsStringHasEmbeddedNull(
|
||||
_In_opt_ HSTRING string,
|
||||
_Out_ BOOL* hasEmbedNull
|
||||
) {
|
||||
return P::SupportsWRL()
|
||||
? P::WindowsStringHasEmbeddedNull(string, hasEmbedNull)
|
||||
: CO_E_DLLNOTFOUND;
|
||||
}
|
||||
|
||||
STDAPI_(BOOL)
|
||||
RoOriginateErrorW(
|
||||
_In_ HRESULT error,
|
||||
_In_ UINT cchMax,
|
||||
_When_(cchMax == 0, _In_reads_or_z_opt_(MAX_ERROR_MESSAGE_CHARS))
|
||||
_When_(cchMax > 0 && cchMax < MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(cchMax))
|
||||
_When_(cchMax >= MAX_ERROR_MESSAGE_CHARS, _In_reads_or_z_(MAX_ERROR_MESSAGE_CHARS)) PCWSTR message
|
||||
) {
|
||||
return P::SupportsWRL()
|
||||
&& P::RoOriginateErrorW(error, cchMax, message);
|
||||
}
|
||||
|
||||
STDAPI_(BOOL)
|
||||
RoOriginateError(
|
||||
_In_ HRESULT error,
|
||||
_In_opt_ HSTRING message
|
||||
) {
|
||||
return P::SupportsWRL() && P::RoOriginateError(error, message);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // Qt < 6.0.0
|
||||
66
Telegram/lib_base/base/platform/win/base_windows_wrl.h
Normal file
66
Telegram/lib_base/base/platform/win/base_windows_wrl.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#define _ROAPI_ // we don't want them from .dll
|
||||
#include <roapi.h>
|
||||
#undef _ROAPI_
|
||||
|
||||
#include <windows.h>
|
||||
#include <wrl/client.h>
|
||||
#include <winstring.h>
|
||||
#include <strsafe.h>
|
||||
#include <intsafe.h>
|
||||
|
||||
namespace base::Platform {
|
||||
|
||||
[[nodiscard]] bool SupportsWRL();
|
||||
|
||||
class StringReferenceWrapper final {
|
||||
public:
|
||||
StringReferenceWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) throw() {
|
||||
HRESULT hr = WindowsCreateStringReference(stringRef, length, &_header, &_hstring);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
~StringReferenceWrapper() {
|
||||
WindowsDeleteString(_hstring);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
StringReferenceWrapper(_In_reads_(N) wchar_t const (&stringRef)[N]) throw() {
|
||||
UINT32 length = N - 1;
|
||||
HRESULT hr = WindowsCreateStringReference(stringRef, length, &_header, &_hstring);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t _>
|
||||
StringReferenceWrapper(_In_reads_(_) wchar_t(&stringRef)[_]) throw() {
|
||||
UINT32 length;
|
||||
HRESULT hr = SizeTToUInt32(wcslen(stringRef), &length);
|
||||
if (!SUCCEEDED(hr)) {
|
||||
RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr);
|
||||
}
|
||||
|
||||
WindowsCreateStringReference(stringRef, length, &_header, &_hstring);
|
||||
}
|
||||
|
||||
HSTRING Get() const throw() {
|
||||
return _hstring;
|
||||
}
|
||||
|
||||
private:
|
||||
HSTRING _hstring;
|
||||
HSTRING_HEADER _header;
|
||||
|
||||
};
|
||||
|
||||
} // namespace base::Platform
|
||||
15
Telegram/lib_base/base/platform/win/wrl/wrl_implements_h.h
Normal file
15
Telegram/lib_base/base/platform/win/wrl/wrl_implements_h.h
Normal file
@@ -0,0 +1,15 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/win/base_windows_wrl.h"
|
||||
|
||||
#pragma warning(push)
|
||||
// class has virtual functions, but destructor is not virtual
|
||||
#pragma warning(disable:4265)
|
||||
#include <wrl/implements.h>
|
||||
#pragma warning(pop)
|
||||
16
Telegram/lib_base/base/platform/win/wrl/wrl_module_h.h
Normal file
16
Telegram/lib_base/base/platform/win/wrl/wrl_module_h.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// This file is part of Desktop App Toolkit,
|
||||
// a set of libraries for developing nice desktop applications.
|
||||
//
|
||||
// For license and copyright information please follow this link:
|
||||
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "base/platform/win/base_windows_wrl.h"
|
||||
|
||||
#pragma warning(push)
|
||||
// class has virtual functions, but destructor is not virtual
|
||||
#pragma warning(disable:4265)
|
||||
#pragma warning(disable:5104)
|
||||
#include <wrl/module.h>
|
||||
#pragma warning(pop)
|
||||
Reference in New Issue
Block a user