最近一段时间,接到一个预研任务。我们的现有系统是QT + C++开发的,现在需要实现一个功能,能让用户在系统运行过程中,随时在UI上打开系统加载的一些C++动态库的源代码,并自动attach到UI的exe进程上进行调试。
  经过技术选型,决定使用当前比较火的vscode来实现。vscode简单来说是一个轻量版的visual studio,支持多种语言的开发,而且在其上进行自定义插件开发也很方便,可以很好地满足我的上述需求。vscode插件开发的相关资料网上很少,本人以前从来未接触过这方面的工作内容,也是一步步自己摸索,并根据自己的理解,经过一个多星期的研究,最终初步完成了一个可用的插件。所以决定把研究过程遇到的问题和踩过的坑写下来,供新手参考,独乐乐不如众乐乐。废话不多说,直接上步骤。
   一 :安装vscode和c++开发扩展
  首先安装vscode,网上很多资料,去官网上下载一个vscode安装包,根据安装向导一步步安装就行。安装完vscode后,需要安装c++的开发扩展,cpptools-win32.vsix。 这个需要打开vscode,在左侧的Extension中安装,可以在  线search extensions搜索该扩展插件,也可以先下载该vsix,选择“Install from VSIX”进行安装。

二 :安装yo和generator-code
  这两个工具很多地方都称为“脚手架”,可以理解为一个可以为你搭建插件框架的工具,它能帮你自动生成插件运行需要的一些文件。其中最重要的是package.json文件,该文件用于配置插件的入口、触发事件、contributes等重要信息。
   小技巧:本来这两个工具可以通过npm在线安装,但是因为公司不能上外网(遇到这种情况,真是无语的很啊),所以这两个工具不能在线安装。但是也不是完全没办法。一个办法就是在GitHub上下载一份别人写好的vscode插件源码,一般都包含有所有必需的文件,可以在此基础上修改,开发自己的插件

三:package.json文件配置
下面就要开始对这个插件进行配置了,该文件最主要几个配置信息如下:
"main": "./src/extension",
此处配置你的插件入口,一般是一个js文件。(vscode是以node.js作为js的运行环境的)。本例中,插件入口在extension.js文件中。

"contributes": {
        "commands": [
            {
                "command": "Hello",
                "title": "Hello,my first plugin"
            },                
        ],
"menus": {
            "editor/context": [
                {
                    "when": "editorFocus",
                    "command": "Hello",
                    "group": "navigation@6"
                },
                
            ]
},
"keybindings": [
            {
                "command": "Hello",
                "key": "ctrl+f10",
                "mac": "cmd+f10",
                "when": "editorTextFocus"
            },
]
}

此处配置插件的“贡献点”,可以添加命令、菜单项、快捷键等等。本例中我们添加一个测试的命令Hello,在编辑器处于焦点时,右键菜单中添加了一个Hello菜单项,并为其设置一个快捷键Ctrl+F10.

"activationEvents": [
        "onLanguage:cpp"
    ],
此处配置插件的激活事件,支持以下几种事件:
onLanguage:${language}
onCommand:${command}
onDebug
workspaceContains:${toplevelfilename}
onFileSystem:${scheme}
onView:${viewId}
onUri
*

回到我们的需求,我们需要在UI上打开c++源码文件,并自动attach到UI的exe进程上。所以我这里把插件的激活事件配置成“OnLanguage::cpp”,意思是每当在vscode中新打开了一个cpp文件时,就激活插件,进入插件入口文件extension.js,开始执行自己的业务逻辑。(特别说一下的是: *表示的是vscode一启动就激活插件,一般不太推荐,因为这样流程不太好控制)

四:extension.js编写
const vscode = require('vscode');  //加载内置vscode开发包,包含vscode的所有API
 
//插件被激活时触发的函数
exports.activate = function(context) {
    console.log('vscode-myplugin被激活');
    require('./hello')(context); // hello命令
    require('./autoAttach')(context); // 自动attach业务逻辑(核心业务)
};

// 插件被释放时触发的函数
exports.deactivate = function() {
    console.log('vscode-myplugin被释放')
};

可以按业务逻辑,分成多个js文件编写。例如我们可以为每个command写一个js,为每种业务逻辑编写一个js。在activate函数中依次执行这些js文件即可。

以下是Hello命令的hello.js代码:

const vscode = require('vscode');
module.exports = function(context) {
    // 注册Hello命令
    context.subscriptions.push(vscode.commands. ('Hello', () => {
        vscode.window.showInformationMessage('Hello!My first Plugin ');
    }));
};
代码比较简单,就是利用vscode.commands的registerCommand这个API注册Hello命令,注意这里注册的命令名称一定要在上面的package.json文件的commands中配置过的,否则会报错。

以下是autoAttach.js文件代码:

const vscode = require('vscode');
var path = require('path');   //处理路径的包
var cp = require('child_process');
module.exports = function(context) {
    //获取当前打开的cpp文件绝对路径
    var curFileName = vscode.window.activeTextEditor.document.fileName;
    console.log('当前打开的文件路径:');
    console.log(curFileName);
    //获取当前cpp文件对应的工作区目录
    let workspaceUri = vscode.Uri.file(path.dirname(curFileName));
    //打开当前cpp文件对应的工作区
    vscode.commands.executeCommand('vscode.openFolder', workspaceUri).then(success => {
    console.log('open folder result:', success);
    //打开工作区的第一个lauch配置(本例配置为一个attach调试)
    const config = vscode.workspace.getConfiguration('launch', vscode.workspace.workspaceFolders[0].uri);
    const configurations = config.get('configurations');
    //获取UI的exe进程号
    cp.exec('tasklist', function(err, stdout, stderr){
            if(err){return console.log(err);}
            stdout.split('\n').filter(function(line){
                var p = line.trim().split(/\s+/), pname = p[0], pid = p[1];
                if(pname.indexOf('TestGui.exe') >= 0 && parseInt(pid)){
                    //修改processId为当前的UI进程ID
                configurations[0].processId = pid;
                    //启动调试器,attach到该进程上开始调试
                vscode.debug.startDebugging( vscode.workspace.workspaceFolders[0], configurations[0], null);
                }
            });
        });
       
    });
};

简单来说就是,通过TestGui.exe启动vscode打开某个cpp文件时,插件就会触发,首先获取该cpp文件的路径,然后打开对应的workspace。获取该workspace的第一个lauch配置,我的第一个lauch配置如下(在workspace的launch.json文件中):

"configurations": [
        {
            "name": "testAttach",
            "type": "cppvsdbg",
            "request": "attach",
            "processId": "${command:pickProcess}"
        },
     {

可以看到这是一个attach调试的配置,这里有几点注意事项:
1    type :如果你使用的是windows的cl.exe这个编译器,那么这个type一定要填cppvsdbg,gdb编译器的话,type填的是cppdbg.
2    request: 因为我的需求是attach到UI进程上调试,所以填的是attach。如果是需要新启动一个进程进行调试,这里需要填launch。
3  processId:这里可以填${command:pickProcess},即调试启动时让用户选择一个进程附加上去。也可以直接填一个固定的process Id,这样调试启动时就直接附加到该进程号对应的进程上了。但是这两种方式都不符合我的需求,因为第一种方式,需要手动选择一个进程才能启动调试,我需要的是自动附加到UI进程。而由于我每次启动UI进程时,UI进程分配到的进程ID都不一样,所以第二种填一个固定进程ID的方式也不行。所以这里采用的方法是,在插件中,根据tasklist这个shell命令实时搜索当前TestGui.exe进程的进程ID,然后修改launch中的processId, 这样插件就可以自动attach到当前的UI进程上了。

五 UI进程打开cpp文件
HMODULE hDllLib = LoadLibraryA("XXX\\TestDll.dll");
if (hDllLib == nullptr)
{
    //cout << "load library failed!" << endl;
}
else
{
    //cout << "load library successfully!" << endl;
    auto pFunc = GetProcAddress(hDllLib, "TestInterface");
    if (pFunc != nullptr)
    {
        pFunc();
HINSTANCE hRtn = ShellExecute(NULL, (LPCWSTR)L"open", (LPCWSTR)L"\"D:\\Users\\UserName\\AppData\\Local\\Programs\\Microsoft VS  Code\\Code.exe\"", 
(LPCWSTR)L"D:\\XXX \\TestAttach.cpp", NULL, SW_SHOW);
 }
else
{
    //cout << "can not get TestInterface!" << endl;
}
}

利用ShellExecute这个WINDOWS的API使用Vscode打开指定的cpp文件。此时cpp文件被打开后,就会自动触发上面的vscode插件,自动attach到UI进程上。

至此第一个vscode插件开发完成,可能有的地方描述不太准确,这也是我的第一个博客,希望大家积极批评指正,今天就写到这吧。
参考资料:https://www.cnblogs.com/liuxianan/p/vscode-plugin-common-api.html

一个vscode自动attach进程的插件开发实例相关推荐

  1. 编写一个VSCode插件

    原文链接: 编写一个VSCode插件 - 愧怍的小站 自从使用过 VSCode 后就再也离不开 VSCode,其轻量的代码编辑器与诸多插件让多数开发者爱不释手.同样我也不例外,一年前的我甚至还特意买本 ...

  2. python发送邮件 python发送qq,163,sohu, xinlang, 126等邮件 python自动发邮件总结及实例说明...

    python发邮件需要掌握两个模块的用法,smtplib和email,这俩模块是python自带的,只需import即可使用.smtplib模块主要负责发送邮件,email模块主要负责构造邮件. sm ...

  3. 个人建议:设置Alt+S快捷键来控制VSCode自动保存切换功能

    经常要修改配置文件或者组件Vue,但是自动保存如果设置了就会导致还没输入完成一个完整代码行,就自动格式化(当时这种情况真的想骂人),但平时编辑Vue页面文件又不想每次都去Ctrl+S保存(毕竟键盘死的 ...

  4. 推荐一个代码自动完成的工具AutoCode

    本文转载:http://www.cnblogs.com/xiaoxiangfeizi/archive/2012/07/24/2605884.html 最近发现了一个代码自动完成工具AutoCode,特 ...

  5. 【Android 逆向】代码调试器开发 ( 代码调试器功能简介 | 设置断点 | 读写内存 | 读写寄存器 | 恢复运行 | Attach 进程 )

    文章目录 一.代码调试器功能简介 二.Attach 进程 一.代码调试器功能简介 代码调试器功能 : 设置断点 : 无论什么类型的调试器 , 都必须可以设置断点 , 运行到断点处 , 挂起被调试进程 ...

  6. Linux OOM 自动杀死进程(转)

    Linux OOM 自动杀死进程 问题描述: 今天上班后,登录一台内网测试服务器,发现部分进程失踪 (Nginx/PHP-FPM/MySQL/Crond). 解决方法: 1.首先启动这些进程,保证正常 ...

  7. java list加入listview_Android ListView自动生成列表条目的实例

    activity_list.xml文件代码如下: xmlns:android="http://schemas.android.com/apk/res/android" androi ...

  8. java socket发送定长报文_一个基于TCP协议的Socket通信实例

    原标题:一个基于TCP协议的Socket通信实例 1. 前言 一般接口对接多以http/https或webservice的方式,socket方式的对接比较少并且会有一些难度.正好前段时间完成了一个so ...

  9. vscode自动加前缀_详解VScode自动补全CSS3前缀插件以及配置无效的解决办法

    1.在vscode中搜索Autoprofixer 2.在安装完成之后要配置 在需要添加前缀的css文件上,右键点击命令面板,输入Autoprefixer CSS就好啦 ps: 如果想要兼容性最好的话, ...

  10. 【chorme插件开发】第四节:html+js实现的功能插件开发实例

    ###html+js实现的功能插件开发实例 插件结构 icon.pngpopup.htmlpopup.jsmanifest.json manifest.json文件配置 { "manifes ...

最新文章

  1. 多表查询事务DCL权限管理
  2. c语言字符指针初始化赋值,C语言_指针变量的赋值与运算,很详细详解
  3. 江苏省计算机考试Python用书,【关注】Python列入高考内容以及全国计算机等级考试!...
  4. php框架--php框架的连贯查询实现原理
  5. O2O概念实践案例: Giftly改变送礼方式
  6. 力扣116. 填充每个节点的下一个右侧节点指针(JavaScript)
  7. WPF 去除头部,实现拖动
  8. 虚拟机下liunx安装jdk
  9. iOS8过渡到iOS9,Xcode6过渡到Xcode7
  10. 中国行政区域(县区级带坐标经纬度)
  11. 【Unity gradle打android包网络连接超时错误 connec xxx ttime out】
  12. 关于手画猫,耳朵涂颜色
  13. 关于win11系统网络连接有效但是无法正常上网的解决办法
  14. 伊拉克COR证书电子电器
  15. 人工智能对学计算机的影响,计算机专业大学生对人工智能对人类的影响分析.docx...
  16. 努比亚android11,努比亚Play开测Android11 填写基本信息即可
  17. MySQL 5.6.22绿色版安装
  18. DNN中的BP和RNN中的BPTT推导
  19. 【苹果CMS技术教程】苹果CMSV10怎么更换模板
  20. 日历控件QCalendarWidget

热门文章

  1. MySQL基础 - 简单查询
  2. 你好Linux!第一篇——Linux的前世今生和应用
  3. 史上最全Android版本号信息:)_我是亲民_新浪博客
  4. MySQL 权限操作
  5. 基因表达相关性——笔记
  6. android studio scala插件,在Android Studio中使用Scala和Java
  7. 高盛发布区块链报告:从理论到实践(中文版)一
  8. 折线图css,echarts实现折线图的代码(附图)
  9. 【转】关于在.Net开发中使用Sqlite的版本选择问题
  10. 百度LBS开放平台个性化地图 制作一款独一无二的地图