原本想要学习一下语法高亮功能,做一个像Notepad++一样的编辑器。
然后就兴冲冲的下载了Notepad++的开源代码准备开始看。
但是整个框架比较复杂,看了一会之后突然发现Notepad++使用的是Scintilla这个很强大的控件,而且也是开源的。所以最后决定在分析Notepad++源代码之前先使用一下Scintilla,然后研究一下Scintilla的源码。
下面是Scintilla 的官方网站:
http://www.scintilla.org/index.html
我们下载源代码。
然后准备编译。参考了下面这个博客:
这里自己在编译makefile文件的时候出了一个错误:我使用了Visual Studio 命令提示(64位)下编译文件,结果编译出来之后的文件无法被vs识别。
一开始一直找不到错误,LoadLibrary 的返回值一直为0,后来用GetLastError()查看错误信息,才发现了原来是dll文件本身编译成了64位。
而我的程序是32位的,所以dll无法识别64位的dll。
后来用32位的 Visual Studio 命令提示重新编译出了32位的dll就对了。32位编译出来的dll是600多K, 而64位编译出来的是900多K。
具体编译的步骤:
打开Visual Studio 命令提示
进到下载好的scintilla文件目录下面的win32目录下面,
nmake -f scintilla.mak clean //清理工程 nmake -f scintilla.mak //编译
接下来主要学习下面两篇文章,一篇是参考官方的文档,另外一篇是国人写的一个翻译文档。
http://www.scintilla.org/ScintillaDoc.html
http://www.cnblogs.com/superanyi/archive/2011/04/07/2008632.html
自己学习的时候是用Win32 SDK C编写。
首先随便拉个Win32下面的应用程序,用windows程序设计里面的第一个对话框程序就好了。
我的目标是做出语法高亮,当然也不是限于这些,因为Scintilla是一个非常强大的库。
首先我们将编译好的SciLexer.dll放入当前目录中, 引入动态链接库:这里特别注意别犯像我这样的新手错误。
这个dll最大的功能就是进行语法解析 Lexer。
hmod = LoadLibrary("SciLexer.DLL"); if (hmod==NULL) { MessageBox(hwndParent, "The Scintilla DLL could not be loaded.", "Error loading Scintilla", MB_OK | MB_ICONERROR); }如果hmod不为0,那么说明我们成功引入了动态链接库。
下载的源码文件里面有Include文件,包含了一些头文件。这里我们将下面两个头文件放到当前目录下。
#include "SciLexer.h" #include "Scintilla.h"
接下来我们可以开始使用这个库里面的Scintilla类。我们可以创建一个窗口子类。
HWND hwndScintilla; hwndScintilla = CreateWindowEx(0, "Scintilla","", WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPCHILDREN, 10,10,500,400,hwndParent,(HMENU)GuiID, hInstance,NULL);
接下来就是发送消息了。这里发送消息有两种方式。第一个方式就是SendMessage的方式,这种方式通俗易懂。第二种方式有点复杂。下面一一来介绍下:
SendMessage(hwndScintilla,sci_command,wparam,lparam);
like:
SendMessage(hwndScintilla,SCI_CREATEDOCUMENT, 0, 0);
这样就发送了窗口消息。我们可以在父窗口的窗口回调函数里面对消息进行处理:
NMHDR *lpnmhdr; [...] case WM_NOTIFY: lpnmhdr = (LPNMHDR) lParam; if(lpnmhdr->hwndFrom==hwndScintilla) { switch(lpnmhdr->code) { case SCN_CHARADDED: /* Hey, Scintilla just told me that a new */ /* character was added to the Edit Control.*/ /* Now i do something cool with that char. */ break; } } break;
int (*fn)(void*,int,int,int); void * ptr; int canundo; fn = (int (__cdecl *)(void *,int,int,int))SendMessage( hwndScintilla,SCI_GETDIRECTFUNCTION,0,0); ptr = (void *)SendMessage(hwndScintilla,SCI_GETDIRECTPOINTER,0,0); canundo = fn(ptr,SCI_CANUNDO,0,0);自己也是新手,纯粹是为了觉得语法高亮好玩才玩的。自己的C语言功底不是很好,上面这段函数有点不太好理解。
int (*fn)(void*,int,int,int);这里应该是定义了一个函数地址,这个函数有4个参数,返回值是int类型
fn = (int (__cdecl *)(void *,int,int,int))SendMessage( hwndScintilla,SCI_GETDIRECTFUNCTION,0,0);这里定义了函数入口地址,相当于我们使用fn函数就是使用SendMessage函数。 不知道这样讲对不对,还请大家指教。
其实这里自己感觉也解释不太清楚,想请大家帮忙指正理解。
比如我自己是这样定义的:
int (*SendEditor)(void*,int,int,int); //快速发送消息 SendEditor = (int (__cdecl *)(void *,int,int,int))SendMessage( hwndScintilla,SCI_GETDIRECTFUNCTION,0,0); ptr = (void *)SendMessage(hwndScintilla,SCI_GETDIRECTPOINTER,0,0); canundo = SendEditor(ptr,SCI_CANUNDO,0,0);
以后自己就使用SendEditor,没有使用SendMessage了。
但是自己不理解的是:c应该没有重载 多态这些概念,我在使用SendEditor的时候里面必须写4个参数。感觉用起来也没方便多少。
自己C++没学多少。想请问下大家如何在C++下面实现该SendEditor的简洁方法?在此感谢大家。