You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
3.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "URIReg.h"
#include <QtGlobal>
#include <QCoreApplication>
#include <QSettings>
#include <QDir>
#include <QDebug>
URIReg URIReg::instance;
URIReg::URIReg() {
}
URIReg::~URIReg() {
}
URIReg& URIReg::getInstance() {
return instance;
}
bool URIReg::reg(const QString& protocolName) {
#ifdef Q_OS_WIN
// 获取当前工作目录
QString appPath = QCoreApplication::applicationFilePath();
#if 0
// 提升权限
if (!runAsAdmin())
return false;
#endif
#if 1
if (!isRunningAsAdmin())
return false;
#endif
// 创建注册表项
#if 0 // 因应用操作注册表的权限问题改成HKEY_CURRENT_USER
QSettings settings("HKEY_CLASSES_ROOT\\" + protocolName, QSettings::NativeFormat);
#else
QSettings settings("HKEY_CURRENT_USER\\Software\\Classes\\" + protocolName, QSettings::NativeFormat);
#endif
// 设置协议描述
settings.setValue("Default", QString("URL:%1 Protocol").arg(protocolName));
settings.sync();
if (QSettings::NoError != settings.status())
return false;
// 标识这是一个URL协议
settings.setValue("URL Protocol", "");
settings.sync();
if (QSettings::NoError != settings.status())
return false;
// 创建命令子项
settings.beginGroup("shell");
settings.beginGroup("open");
settings.beginGroup("command");
// 设置启动命令(注意转义 %1
QString command = QString("\"%1\" \"%2\"").arg(appPath).arg("%1");
settings.setValue("Default", command);
settings.endGroup();
settings.endGroup();
settings.endGroup();
QSettings::Status s = settings.status();
// 验证写入结果
if (QSettings::NoError != settings.status())
return false;
return true;
#else
// TODO:非Win平台下未实现
assert(0);
return false;
#endif
}
#ifdef Q_OS_WIN
#include <windows.h>
#include <shellapi.h>
bool URIReg::runAsAdmin() {
wchar_t path[MAX_PATH];
GetModuleFileNameW(nullptr, path, MAX_PATH);
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.lpVerb = L"runas";
sei.lpFile = path;
sei.hwnd = nullptr;
sei.nShow = SW_NORMAL;
if (!ShellExecuteExW(&sei)) {
qWarning() << QStringLiteral("提权失败:") << GetLastError();
return false;
}
return true;
}
// 检查是否以管理员权限运行
bool URIReg::isRunningAsAdmin() {
HANDLE hToken;
BOOL isElevated = FALSE;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
TOKEN_ELEVATION elevation;
DWORD cbSize = sizeof(TOKEN_ELEVATION);
GetTokenInformation(hToken, TokenElevation, &elevation, cbSize, &cbSize);
CloseHandle(hToken);
isElevated = elevation.TokenIsElevated;
}
return isElevated != FALSE;
}
#include <aclapi.h>
#include <sddl.h>
void URIReg::fixRegistryPermissions(const QString& keyPath) {
HKEY hKey;
LONG result = RegOpenKeyExW(
HKEY_CURRENT_USER,
keyPath.toStdWString().c_str(),
0, // 选项必须为0
KEY_READ | KEY_WRITE, // 读写权限,
&hKey
);
if (result == ERROR_SUCCESS) {
// 重置为默认权限
PSECURITY_DESCRIPTOR sd;
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(
L"D:(A;;KA;;;SY)(A;;KA;;;BA)(A;;KR;;;IU)", // 标准用户权限
SDDL_REVISION_1,
&sd,
nullptr)) {
RegSetKeySecurity(hKey, DACL_SECURITY_INFORMATION, sd);
LocalFree(sd);
}
RegCloseKey(hKey);
}
}
bool URIReg::writeUrlProtocol(const QString& protocol) {
HKEY hKey;
DWORD disp;
QString fullPath = QString("Software\\Classes\\") + protocol;
LONG res = RegCreateKeyExW(
HKEY_CURRENT_USER,
fullPath.toStdWString().c_str(),
0,
nullptr,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
nullptr,
&hKey,
&disp
);
if (res == ERROR_SUCCESS) {
// 写入协议标识
DWORD zero = 0;
RegSetValueExW(hKey, L"URL Protocol", 0, REG_SZ, (BYTE*)L"", 2);
// 写入描述
std::wstring desc = L"URL:" + protocol.toStdWString() + L" Protocol";
RegSetValueExW(hKey, nullptr, 0, REG_SZ, (BYTE*)desc.c_str(), (desc.size() + 1) * sizeof(wchar_t));
RegCloseKey(hKey);
return true;
}
return false;
}
#endif // Q_OS_WIN