windows 平台如何点击网页上的url ,会打开远程桌面连接服务器

你可以使用自定义协议方案(Protocol Scheme)实现网页上点击URL后自动启动远程桌面连接(mstsc),参考你提供的C++代码思路,如下实现:

第一步:注册自定义协议

使用类似openmstsc://协议。

注册示例 (reg 文件形式)
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\openmstsc]
@="URL:openmstsc Protocol"
"URL Protocol"=""

[HKEY_CLASSES_ROOT\openmstsc\shell\open\command]
@="\"C:\\your-path\\open_mstsc.exe\" \"%1\""

或通过你的C++代码自动完成注册(代码里已经包含该功能)。


第二步:网页中调用协议URL

网页端代码(简单HTML):

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>远程桌面连接示例</title>
</head>
<body>
    <a href="openmstsc://192.168.1.100:3389">连接远程桌面 192.168.1.100</a>
</body>
</html>

注意:

  • 点击此链接时,浏览器会提示用户是否允许调用该协议(首次使用时会询问),确认即可。

第三步:你的C++程序实现要点(已提供,以下强调注意点)

你的C++程序中关键实现点(你代码中已经包含了):

  • 解析传入的URL,提取IP:端口
  • 使用ShellExecuteExW调用mstsc.exe并传入/v:IP:Port参数。

示例(摘录):

void OpenWithMstsc(const std::wstring& serverIP) {
    if (serverIP.empty()) return;

    std::wstring mstscArgs = L"/v:" + serverIP;

    SHELLEXECUTEINFOW sei = { sizeof(sei) };
    sei.lpFile = L"mstsc.exe";
    sei.lpParameters = mstscArgs.c_str();
    sei.nShow = SW_SHOWNORMAL;
    sei.fMask = SEE_MASK_NOASYNC;

    ShellExecuteExW(&sei);
}

完整流程说明

  1. 网页链接点击 → 浏览器触发openmstsc://IP:Port
  2. 浏览器调用注册好的协议→ 执行open_mstsc.exe,传入参数。
  3. 程序解析URL → 调用mstsc.exe→ 远程桌面客户端打开。

这样即可实现点击网页上的链接自动打开远程桌面连接的功能。

// open_mstsc.cpp
// C++ 重写版本:实现与 C# 相同功能,包括注册自定义协议、解析 URL,并通过 WPS 打开文件,且不弹出控制台窗口。
//语言功能 "结构化绑定" 需要编译器标志 "/std:c++17"
//链接器-》系统-》子系统-》窗口模式
#include <windows.h>
#include <shlwapi.h>
#include <iostream>
#include <string>
#include <urlmon.h>
#include <shellapi.h>
#include <algorithm> // for std::transform
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "urlmon.lib")
#include <cctype>
const std::wstring PROTOCOL_NAME = L"openMstsc";
#include <windows.h>
#include <shellapi.h>

bool IsRunAsAdmin() {
    BOOL isAdmin = FALSE;
    PSID adminGroup;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

    if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
        0, 0, 0, 0, 0, 0, &adminGroup)) {
        CheckTokenMembership(NULL, adminGroup, &isAdmin);
        FreeSid(adminGroup);
    }
    return isAdmin;
}

void RelaunchAsAdmin() {
    wchar_t exePath[MAX_PATH];
    GetModuleFileNameW(NULL, exePath, MAX_PATH);

    SHELLEXECUTEINFOW sei = { sizeof(sei) };
    sei.lpVerb = L"runas"; // 以管理员权限运行
    sei.lpFile = exePath;
    sei.nShow = SW_SHOWNORMAL;
    sei.fMask = SEE_MASK_NOASYNC;

    if (ShellExecuteExW(&sei)) {
        ExitProcess(0); // 关闭当前进程
    }
}
// 替代 HttpUtility.UrlDecode 的简单实现
// 使用 UrlUnescapeW API 进行解码
static std::wstring UrlDecode(const std::wstring& encoded) {
    if (encoded.empty()) return L"";

    // 预留缓冲区存放解码后的结果
    const size_t BUFFER_SIZE = 4096;
    wchar_t buffer[BUFFER_SIZE];
    wcsncpy_s(buffer, encoded.c_str(), BUFFER_SIZE);

    DWORD dwSize = (DWORD)BUFFER_SIZE;
    HRESULT hr = UrlUnescapeW(buffer, NULL, &dwSize, URL_UNESCAPE_INPLACE);
    if (SUCCEEDED(hr)) {
        return std::wstring(buffer);
    }
    else {
        // 如果解码失败,可以根据需求返回空字符串或原始值
        return L"";
    }
}

 



static std::wstring ProcessServerIP(const std::wstring& inputUrl, const std::wstring& protocolName)
{
    // 1) 构造 "{protocol}://" 的小写形式
    std::wstring lowerProtocol = protocolName;
    std::transform(lowerProtocol.begin(), lowerProtocol.end(), lowerProtocol.begin(), ::towlower);
    std::wstring protocolPrefix = lowerProtocol + L"://";

    // 2) 转换 inputUrl 为小写进行查找
    std::wstring lowerInput = inputUrl;
    std::transform(lowerInput.begin(), lowerInput.end(), lowerInput.begin(), ::towlower);

    // 3) 移除 "protocol://"
    std::wstring url;
    size_t pos = lowerInput.find(protocolPrefix);
    if (pos != std::wstring::npos)
    {
        url = inputUrl.substr(pos + protocolPrefix.size());
    }
    else
    {
        url = inputUrl;  // 原始 URL
    }

    // 4) URL 解码(假设 UrlDecode 是可用函数)
    url = UrlDecode(url);

    // 5) 去除路径部分,仅保留 "host:port"
    size_t pathPos = url.find(L'/');
    if (pathPos != std::wstring::npos)
    {
        url = url.substr(0, pathPos);
    }

    return url;
}


//-----------------------------------------------------------
// 下面是原有的函数声明与实现
//-----------------------------------------------------------

void RegisterUrlScheme(const std::wstring& protocol, const std::wstring& exePath);
std::wstring GetRegisteredPath(const std::wstring& protocol);

void OpenWithMstsc(const std::wstring& fileUrl);
std::pair<std::wstring, std::wstring> GetWpsLauncherPath();
void EnsureUrlScheme(const std::wstring& protocol);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
//int main(){

    if (!IsRunAsAdmin()) {
        RelaunchAsAdmin(); // 如果不是管理员权限,则重新以管理员权限运行
        return 0;
    }
    EnsureUrlScheme(PROTOCOL_NAME);

    int argc;
    LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    if (argv == NULL) return 0;

    if (argc < 2) {
        //MessageBoxW(NULL, L"⚠️ 未检测到 URL 参数。", L"提示", MB_OK | MB_ICONWARNING);
        return 0;
    }
     

    // 调用新版 ProcessUrl
    std::wstring url = ProcessServerIP(argv[1], PROTOCOL_NAME);



    if (PathIsURLW(url.c_str())) {
        OpenWithMstsc(url);
    }
    else {
 
    }

    LocalFree(argv);
    return 0;
}

void EnsureUrlScheme(const std::wstring& protocol) {
    wchar_t exePath[MAX_PATH];
    GetModuleFileNameW(NULL, exePath, MAX_PATH);
    std::wstring registeredPath = GetRegisteredPath(protocol);

    if (registeredPath.empty() || !_wcsicmp(registeredPath.c_str(), exePath) == 0) {
        RegisterUrlScheme(protocol, exePath);
    }
}

std::wstring GetRegisteredPath(const std::wstring& protocol) {
    HKEY hKey;
    std::wstring regPath = L"";
    std::wstring keyPath = protocol + L"\\shell\\open\\command";
    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyPath.c_str(), 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
        wchar_t value[MAX_PATH];
        DWORD value_length = sizeof(value);
        if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)value, &value_length) == ERROR_SUCCESS) {
            std::wstring commandLine(value);
            size_t firstQuoteEnd = commandLine.find(L'"', 1);
            if (firstQuoteEnd != std::wstring::npos) {
                regPath = commandLine.substr(1, firstQuoteEnd - 1);
            }
        }
        RegCloseKey(hKey);
    }
    return regPath;
}

void RegisterUrlScheme(const std::wstring& protocol, const std::wstring& exePath) {
    HKEY hKey;
    std::wstring keyPath = protocol;
    if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyPath.c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) {
        RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE*)(L"URL:" + protocol + L" Protocol").c_str(),
            (DWORD)((protocol.size() + 10) * sizeof(wchar_t)));
        RegSetValueExW(hKey, L"URL Protocol", 0, REG_SZ, (const BYTE*)L"", sizeof(wchar_t));
        HKEY hCommandKey;
        if (RegCreateKeyExW(hKey, L"shell\\open\\command", 0, NULL, 0, KEY_WRITE, NULL, &hCommandKey, NULL) == ERROR_SUCCESS) {
            std::wstring command = L"\"" + exePath + L"\" \"%1\"";
            RegSetValueExW(hCommandKey, NULL, 0, REG_SZ, (const BYTE*)command.c_str(), (DWORD)(command.size() * sizeof(wchar_t)));
            RegCloseKey(hCommandKey);
        }
        RegCloseKey(hKey);
        MessageBoxW(NULL, L"远程组件注册成功。", L"成功", MB_OK | MB_ICONINFORMATION);
    }
}
 
void OpenWithMstsc(const std::wstring& serverIP) {
    if (serverIP.empty()) {
        // MessageBoxW(NULL, L"❌ 服务器 IP 不能为空。", L"错误", MB_OK | MB_ICONERROR);
        return;
    }

    // 远程桌面连接的完整命令行参数
    std::wstring mstscArgs = L"/v:" + serverIP;

    SHELLEXECUTEINFOW sei = { sizeof(sei) };
    sei.lpFile = L"mstsc.exe";  // 远程桌面客户端
    sei.lpParameters = mstscArgs.c_str();
    sei.nShow = SW_SHOWNORMAL;
    sei.fMask = SEE_MASK_NOASYNC;

    if (!ShellExecuteExW(&sei)) {
        // MessageBoxW(NULL, L"❌ 无法启动远程桌面连接。", L"错误", MB_OK | MB_ICONERROR);
    }
}

注意上面代码要以管理员权限运行才能正确写入注册表,否则失败

下面将继续实现一下unbuntu上如何实现类似方法

sudo apt install freerdp2-x11  
xfreerdp /v:10.10.10.11:33389 /u:username /p:passwrod /cert-ignore /dynamic-resolution or( /w:1440 /h:900)


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/983377.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从零开始学机器学习——线性和多项式回归

首先给大家介绍一个很好用的学习地址&#xff1a;https://cloudstudio.net/columns 在之前的学习中&#xff0c;我们已经对数据的准备工作以及数据可视化有了一定的了解。今天&#xff0c;我们将深入探讨基本线性回归和多项式回归的概念与应用。 如果在过程中涉及到一些数学知…

【数据结构初阶第十八节】八大排序系列(上篇)—[详细动态图解+代码解析]

看似不起眼的日复一日&#xff0c;总会在某一天让你看到坚持的意义。​​​​​​云边有个稻草人-CSDN博客 hello&#xff0c;好久不见&#xff01; 目录 一. 排序的概念及运用 1. 概念 2. 运用 3. 常见排序算法 二. 实现常见排序算法 1. 插入排序 &#xff08;1&…

SPI驱动五) -- SPI_DAC上机实验(使用spidev)

文章目录 参考资料&#xff1a;一、DAC硬件1.1 原理图1.2 扩展板连接图1.3 DAC原理 二、编写APP三、编写设备树四、上机实验五、Bug分析六、总结 参考资料&#xff1a; 参考资料&#xff1a; 内核驱动&#xff1a;drivers\spi\spidev.c 内核提供的测试程序&#xff1a;tools\…

基于Asp.net的驾校管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

Spring (八)AOP-切面编程的使用

目录 实现步骤&#xff1a; 1 导入AOP依赖 2 编写切面Aspect 3 编写通知方法 4 指定切入点表达式 5 测试AOP动态织入 图示&#xff1a; 实现步骤&#xff1a; 1 导入AOP依赖 <!-- Spring Boot AOP依赖 --><dependency><groupId>org.springframework.b…

阿里云CTF2025 ---Web

ezoj 啊&#xff1f;怎么整个五个算法题给CTF选手做&#xff1f;&#xff1f;这我不得不展示一下真正的技术把测评机打穿。 可以看到源码 import os import subprocess import uuid import json from flask import Flask, request, jsonify, send_file from pathlib import Pa…

WSL(ubunt)中使用ollama部署deepseek-7b

想在自己的Win11电脑上部署Linux的DeepSeek模型&#xff0c;但在网上一直没有找到合适的相应教程&#xff0c;自己查询各种网上资源&#xff0c;以及询问一些AI大模型后成功安装&#xff0c;并整理了以下步骤。仅作为个人学习笔记使用&#xff0c;由于本人对各方面知识掌握不足…

蓝桥杯国赛—路径之谜(dfs详细解法)

一.题目 二.dfs解法 使用dfs算法可以递归遍历所有可能路径&#xff0c;如果找到错误的路径就进行回溯&#xff0c;只有找到正确的路径才会输出 public class Main {static class pair{int x;int y;public pair(int x,int y){this.x x;this.y y;} }public static void bfs()…

Jenkins在Windows上的使用(二):自动拉取、打包、部署

&#xff08;一&#xff09;Jenkins全局配置 访问部署好的Jenkins服务器网址localhost:8080&#xff0c;完成默认插件的安装后&#xff0c;接下来将使用SSH登录远程主机以实现自动化部署。 1. 配置插件 选择dashboard->Manage Jenkins->plugins 安装下面两个插件  …

记录小白使用 Cursor 开发第一个微信小程序(一):注册账号及下载工具(250308)

文章目录 记录小白使用 Cursor 开发第一个微信小程序&#xff08;一&#xff09;&#xff1a;注册账号及下载工具&#xff08;250308&#xff09;一、微信小程序注册摘要1.1 注册流程要点 二、小程序发布流程三、下载工具 记录小白使用 Cursor 开发第一个微信小程序&#xff08…

蓝耘智算 + 通义万相 2.1:为 AIGC 装上 “智能翅膀”,翱翔创作新天空

1. 引言&#xff1a;AIGC 的崛起与挑战 在过去几年中&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;技术突飞猛进。AIGC 涉及了文本生成、图像创作、音乐创作、视频制作等多个领域&#xff0c;并逐渐渗透到日常生活的方方面面。传统的内容创作方式已经被许多人类创…

C/C++中使用CopyFile、CopyFileEx原理、用法、区别及分别在哪些场景使用

文章目录 1. CopyFile原理函数原型返回值用法示例适用场景 2. CopyFileEx原理函数原型返回值用法示例适用场景 3. 核心区别4. 选择建议5. 常见问题6.区别 在Windows系统编程中&#xff0c;CopyFile和CopyFileEx是用于文件复制的两个API函数。它们的核心区别在于功能扩展性和控制…

计算机性能指标(计网笔记)

计算机性能指标&#xff1a;速率、带宽、吞吐率、时延、时延带宽积、往返时间RTT、利用率 速率 数据的传输速率&#xff0c;单位bit/s&#xff0c;或kbit/s&#xff0c;Mbit/s&#xff0c;Gbit/s 4*10**10bit/s40Gbit/s 常用带宽单位&#xff1a; 千比每秒kb/s 兆比每秒Mb/s…

Python基于Django的医用耗材网上申领系统【附源码、文档说明】

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

php代码审计工具-rips

代码审计 代码审计就是检查所写的代码中是否有漏洞&#xff0c;检查程序的源代码是否有权限从而被黑客攻击&#xff0c;同时也检查了书写的代码是否规范。通过自动化的审查和人工审查的方式&#xff0c;逐行检查源代码&#xff0c;发现源代码中安全缺陷所造成的漏洞&#xff0…

工作学习笔记:HarmonyOS 核心术语速查表(v14 实战版)

作为在 HarmonyOS 开发一线摸爬滚打的工程师&#xff0c;笔者在 v14 版本迭代中整理了这份带血的实战术语表。 一、架构基础术语速查 A 系列术语 术语官方定义笔者解读&#xff08;v14 实战版&#xff09;开发陷阱 & 解决方案abc 文件ArkCompiler 生成的字节码文件打包时…

Trae IDE新建C#工程

目录 1 结论 2 项目结构 3 项目代码 1 结论 新建C#工程来说&#xff0c;Trae的Chat比DeepSeek的Coder好用。 2 项目结构 MyWinFormsApp/ │ ├── Program.cs ├── Form1.cs ├── Form1.Designer.cs ├── MyResources/ │ └── MyResources.resx └── MyWin…

大数据学习(55)-BI工具数据分析的使用

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主哦&#x1f91…

Apache Kafka单节点极速部署指南:10分钟搭建开发单节点环境

Apache Kafka单节点极速部署指南&#xff1a;10分钟搭建开发单节点环境 Kafka简介&#xff1a; Apache Kafka是由LinkedIn开发并捐赠给Apache基金会的分布式流处理平台&#xff0c;现已成为实时数据管道和流应用领域的行业标准。它基于高吞吐、低延迟的设计理念&#xff0c;能够…

【干货教程】Windows电脑本地部署运行DeepSeek R1大模型(基于Ollama和Chatbox)

文章目录 一、环境准备二、安装Ollama2.1 访问Ollama官方网站2.2 下载适用于Windows的安装包2.3 安装Ollama安装包2.4 指定Ollama安装目录2.5 指定Ollama的大模型的存储目录 三、选择DeepSeek R1模型四、下载并运行DeepSeek R1模型五、常见问题解答六、使用Chatbox进行交互6.1 …