notepad++ c++版 插件开发入门

Notepad++的插件开发可以去它的官网下载模板,提供了c/c++,Delphi,c#等语言的插件模板,这里提供一下c++的开发模板.点击下载

下载下来以后是这么些文件


这个工程是能直接编译跑过的,它实现了两个命令, HelloNotepad++ 和Hello (with dialog)

前者是实现了新建一个文档并输入了一段话,后者仅仅是弹出个MessageBox,并不是我们想的是一个dock窗体.

这里先解释一下各个文件是干嘛用的.

menuCmdID.h的意义跟他的名字一样,里面是定义了notepad++里面各个菜单项的id值,应该是点击了它对应的菜单触发了相应的回调的时候用得到,我这次的开发并没有用到这个文件里面的值.

Notepad_plus_msgs.h里面则定义了一些枚举值,比如我们获取到的当前编辑状态是什么语言,其对应的枚举值在LangType里面就可以对应上,其中最主要的还是定义了notepad++本身的一些操作会促发的消息的枚举值,比如打开了文档,保存了文档,这些都是通过一个函数传过来给你的,你就需要根据类型去区分这次的操作是什么,从而做出响应

PluginDefinition.h里面比较简单,就定义了几个函数跟插件的一些信息,比如pluginInit是插件加载的时候调用的, commandMenuInit是初始化菜单用的,每个函数的顶部也有相关的英文说明.我们的每一个命令,都是要对应一个函数的,那些函数也可以定义在这个头文件里面, PluginDefinition.cpp是它里面的每个函数的实现.

PluginInterface.h就是整个插件跟notepad++交互的入口了,它定义了一些导出函数,比如:

void setInfo(NppData),是将notepad++的句柄传递过来,我们根据句柄,就可以给它发送一些信号,这是我们能做二次开发的前提.

const TCHAR * getName()是返回这个插件的名字.

FuncItem * getFuncsArray(int *)是获取我们所有的命令信息,我们自定义的命令都是没有参数跟返回值的.我们的命令是要以数组的方式存起来, int* 是用来获取我们的命令个数的,返回值是数组的首地址.

void beNotified(SCNotification *).这个函数就厉害了,这就是notepad++每次发生变化的时候用来通知我们的回调函数,无论是文件操作发生了变化或者是文本里面的内容发生了变化,比如你打开了文档,或者在文档里面新增或者删除了个字符,都会反应到这个函数里面. SCNotification这个结构体的内容非常多,里面每一项变量都列举了哪些消息会用到它.

LRESULT messageProc(UINT Message, WPARAM wParam, LPARAM lParam) 这个好像是接收notepad++的窗体信号的,比如移动了它,最大化了,最小化了等,这个函数我没有用到.

然后就是resource.h了.就是在里面定义一些资源id而已

Scintilla.h这个也很重要.在介绍这个之前,得先说明一下,notepad++的语法分析,语法高亮,智能提示,文本编辑等这些很重要的东西是基于Scintilla做的,还有其他基于Scintilla做的编辑器,比如notepad2, SciTE等,这个库在windows平台上就是一个窗体控件(这个东西也封装到qt上了,有机会一定要试一试),通过windows消息进行交互,你可以给他发一些消息,然后告诉他你应该做哪些事情,应该显示成什么样子,当他发生了改变,它也会给你发消息(通过beNotified),告诉你他哪里变了.所以Scintilla.h这里文件很重要,是交互的基础,是双方做的一个约定.里面基本都是一些宏定义跟结构体,关于这些宏定义跟结构体,在这里http://www.scintilla.org/ScintillaDoc.html可以找到英文的解释,做notepad++的插件开发 ,很多的工作都是在找我们需要用到的功能,是通过哪个消息去控制的.

最后就是NppPluginDemo.cpp了,这个东西里面主要放了DllMain,dll加载的入口函数,跟PluginInterface.h里面的一些导出函数的实现.然后我们如果是支持UNICODE字符集的话,还会有一个isUnicode()的导出函数.

 

以上就是官方给的例子里面用到的文件说明了,官方还提供一些文件,但是这里没用到,比如DockingFeature文件夹里面的东西,那个是跟窗体有关的,后面会讲到.

以上的工程编译以后是个dll,放在notepad++的plugins文件夹,再打开软件,就会在插件菜单选项卡下看到这个插件了.

 

下面我们来看一下这个命令是怎么构成的.


struct FuncItem {
         TCHAR_itemName[nbChar];
         PFUNCPLUGINCMD _pFunc;
         int _cmdID;
         bool _init2Check;
         ShortcutKey *_pShKey;
};



FuncItem结构体就保存了命令的所有信息,其中_itemName是命令名字,不能超过64个字节, _pFunc是函数指针,要求无返回值无参数, _cmdID这个是注册以后的id值,这个我们不用管,是notepad++加载我们的命令以后去设置的,我们后面比如要做个有图标的选项卡,比如这些

就可以去取这个菜单id来使用了. _init2Check这个是用来判断菜单前面是不是有个勾勾,标识菜单状态用的. ShortcutKey就是默认快捷键了,它的结构体一看就明白,无须多说.

 

设置好命令的这些参数,我们就可以在命令对应的函数里面写我们的响应代码了,我们是通过句柄来发送消息的,下面我们来看一下hello这个命令.

void hello()
{
    // Open a new document
    ::SendMessage(nppData._nppHandle, NPPM_MENUCOMMAND, 0, IDM_FILE_NEW);

    // Get the current scintilla
    int which = -1;
    ::SendMessage(nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, (LPARAM)&which);
    if (which == -1)
        return;
    HWND curScintilla = (which == 0)?nppData._scintillaMainHandle:nppData._scintillaSecondHandle;

    // Say hello now :
    // Scintilla control has no Unicode mode, so we use (char *) here
    ::SendMessage(curScintilla, SCI_SETTEXT, 0, (LPARAM)"Hello, Notepad++!");
}
::SendMessage(nppData._nppHandle, NPPM_MENUCOMMAND, 0,IDM_FILE_NEW);

这里发送了一个系统消息,句柄就是nppData._nppHandle,nppData这个是一个全局静态的变量,它里面存放了notepad++的句柄跟Scintilla的句柄,但是Scintilla有两个,应该是考虑了文档对比等功能的时候要用两个编辑框吧,一般我们用_scintillaMainHandle就可以了.

然后这个消息的第二个参数是NPPM_MENUCOMMAND,代表是菜单消息的,然后最后是IDM_FILE_NEW,就是相当于点击了文件新建的菜单选项了,换成其他的比如IDM_FILE_CLOSE啊就是关闭文档了.

然后第二步是获取scintilla句柄,代码是

int which = -1;

   ::SendMessage(nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0,(LPARAM)&which);

    if (which == -1)

        return;

    HWND curScintilla = (which== 0)?nppData._scintillaMainHandle:nppData._scintillaSecondHandle;

还是先通过notepad++的句柄和GETCURRENTSCINTILLA,获取scintilla的状态,是0就是main那个句柄,否则就是second那个句柄,如果返回-1,那么就是没有激活的编辑框

第三步就是往里面写内容了

::SendMessage(curScintilla, SCI_SETTEXT, 0, (LPARAM)"Hello,Notepad++!");

通过scintilla的句柄和SETTEXT这个信号变量,然后在最后的参数里面写上要设置的文本的内容.就完成了文本的设置.

 

从这里来看,做notepad++的开发也并不难,只要去摸清楚那些操作对应的信号枚举值跟参数,就可以了,具体就可以去scintilla官网查文档了.

 

入门开发就是这么简单.

你可能感兴趣的:(c++)