讓我們寫一個 Win32 文本編輯器吧 - 1. 簡介
在之前的一篇文章 《曾經我認為C語言就是個弟弟》 中,我們通過使用
Windows
系統自帶的EDIT
控件,創建了一個簡單的文本編輯器。而且在文章的最后,還承諾要不使用EDIT
控件,自己制作一個十六進制編輯器。后來想到,既然十六進制編輯器都做了,作為一個程序員,不如寫一個文本編輯器吧,既可以編輯二進制,又可以編輯文本,豈不美哉。
由於實現一個編輯器的復雜性相對比較大,一篇內容肯定完不成。所以,這里決定將整個過程作為一個系列來編輯。
本篇是系列的第一篇。在本篇文章中,將會對我們期望獲得的結果進行簡單的描述,並進行基礎代碼框架進行構建。
本文主要包含兩個部分,如下:
- 項目簡介
在項目簡介部分,將會對我們要實現的目標編輯器的樣子,以及使用方法進行介紹。同時,也會對本系列接下來的文章要討論的主題進行大致說明。
- 基礎代碼框架搭建
在代碼框架搭建部分,將會對項目的創建,設置進行說明。並編輯我們的基礎代碼。
1. 項目簡介
a. 目標
在
Windows11
中,已經將記事本的編輯控件由EDIT
替換為RichEditD2DPT
,詳情參考Windows 11 Notepad
。但是由於關於RichEditD2DPT
控件的描述太少,不知道其具體的用方法。
所以,這里我們以EDIT
控件的接口為准,並實現附加功能。
在此,我們的目標是:通過 C
語言,調用 Win32
接口,生成一個文本編輯器。目標編輯器除了實現和 Windows
提供的默認文本編輯器 EDIT
的所有消息處理,還提供如下功能:
-
可以設置字體顏色
對於
EDIT
控件,雖然可以設置其文本字體,但是沒有設置顏色的方法。 -
可以編輯比較大的文件
對於平時的文件編輯器來說,編輯小文件基本上都差不多,但是當遇到比較大的文件時(比如1G),很可能無能為力,甚至卡死。
所以,既然我們要做一個新的編輯器,自然要考慮大文件的編輯問題。 -
采取
Direct Write
方式實現,而不是和普通的編輯器一樣,通過GDI
。做此選擇的原因,除了因為
Direct Write
支持顏色之外,還有一些其它優點,詳情可以點擊Direct Write
進行參考。 -
支持
EDIT控件
的所有消息。為了使得舊
Win32
代碼更好的使用本編輯器,所有EDIT
控件支持的操作,本項目都應該支持。 -
處理
\r\n
此選擇和
Windows 11
中的選擇具有相同的理由,為了更好的處理換行。 -
支持撤銷操作/恢復上一步操作
在編輯文本時,難免會想恢復到不久之前的版本,撤銷操作允許你做到這個。而當你后悔撤銷的時候,也應該能夠恢復到最新版本,恢復上一步允許你做到重新執行你之前的操作。
-
支持
Unicode
編碼 -
可以設置注解
在編輯時,尤其是要編輯二進制文件時,我們有時候可能要對某個字節,或某段文本進行注解。我們的編輯器允許提供一個注解結構,以在顯示文檔時,可以進行注解顯示。
-
可以進行二進制文件編輯。
二進制編輯雖然不常用,但是,不能在需要用的時候找不到。所以,這里提供了二進制編輯功能。此功能和注解相結合,就可以進行輔助二進制文件的分析。
b. 目標編輯器的樣子
作為一個現代的編輯器,我們希望它有一般編輯器都應該有的能力,下面是一個編輯器的例子:

不難看到,作為一個編輯器,應該支持行號,高亮,多字體,滾動條等內容。這在我們的編輯器中,都將一一實現,並詳細描述實現過程。
c. 項目結構
對於本項目來說,一共包含兩個子項目,如下:
- vicapp:
用於對編輯器控件進行調用的樣例程序 - vitality-controls:
編輯器控件的實現項目,將作為一個DLL
文件提供給調用者。
d. 參考鏈接
代碼地址:https://github.com/vitalitylee/vitality-controls
2. 基礎代碼框架搭建
接下來,我們詳細說明整個項目的構建過程。
a. 打開 Visual Studio
,並點擊創建新項目
如下:
b. 在創建新項目
對話框中,選擇空項目,並點擊下一步
,如下:
c. 在配置新項目
對話框中,設置項目內容,如下:
d. 右鍵項目vitality-conrols
,並點擊屬性,彈出屬性
對話框,如下:
e. 在常規
選項卡中,設置配置類型為 動態庫
,如下:
f. 一次點擊配置屬性
->鏈接器
->系統
,並設置子系統
為窗口
,如下:
g. 鼠標右鍵源文件
文件夾,選擇添加
->新建項
,彈出添加新項
對話框,如下:
注意,這里添加
.c
文件,而不是.cpp
。
h. 輸入 DLL
的入口代碼,如下:
#include <Windows.h>
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
i. 添加預處理聲明
再次打開項目 vitality-controls
的屬性頁面,不難發現,比添加源文件之前,左側多了一個C/C++
節點,左側依次選擇配置屬性
->C/C++
->預處理器
選項,在右側的預處理器定義
中,添加 VITALITY_CONTROLS_EXPORTS
聲明,最終的值應為_DEBUG;VITALITY_CONTROLS_EXPORTS;_CONSOLE;%(PreprocessorDefinitions)
,如下圖所示:
j. 添加接口聲明文件
為了在兩個項目中公用一套代碼,新建的.h
文件,放置在了解決方案根目錄下的shared-include
目錄下,如下:
k. 修改接口代碼
向新建的vitality-controls.h
文件中,輸入如下代碼:
#pragma once
#ifdef VITALITY_CONTROLS_EXPORTS
#define VIC_API __declspec(dllexport)
#else
#define VIC_API __declspec(dllimport)
#endif // VITALITY_CONTROLS_EXPORTS
#include <stdio.h>
VIC_API void vic_prints(const char* str);
並向main.c
中添加新建的vitality-controls.h
文件引用,並添加vic_prints
函數實現,修改后代碼如下:
#include <Windows.h>
#include "../../shared-include/vitality-controls.h"
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
VIC_API void vic_prints(const char* str) {
puts(str);
}
l. 生成接口
鼠標右鍵解決方案,並點擊重新生成解決方案
快捷菜單,如下:
最終,你將得到一個編譯好的vitality-controls.dll
文件,如下:
m. 查看導出函數是否正常導出
點擊操作系統的開始
菜單,並點擊Developer Command Prompt for VS XXXX
,其中XXXX
隨着你使用的Visual Studio
版本不同而不同,本文中使用的版本為Visual Studio 2022
。
所以,顯示如下:
點擊菜單后,會出現命令行窗口,在窗口中輸入命令cd/d [path]
切換到目標文件所在目錄,其中[path]
為你生成的目標 DLL
的所在目錄,如:
切換到目標目錄,就可以使用dumpbin
查看導出函數。在命令行中輸入dumprin /exports vitality-controls.dll
,看到如下內容,說明你生成成功了:
n. 新建測試項目
右鍵解決方案
, 點擊菜單添加
->新建項目
,根據之前的步驟,添加一個新建項目 vicapp
,添加主文件vicapp-main.c
,並輸入如下代碼:
#include "../../shared-include/vitality-controls.h"
int main(int argc, char** argv) {
vic_prints("hello vic.");
return 0;
}
如下所示:
o. 設置啟動項目
右鍵 vicapp
項目,並點擊設為啟動項目
菜單,如下:
設置完成后,點擊啟動按鈕,將默認啟動啟動項目
。
p. 添加項目引用
為了可以使得 vicapp
程序能夠引用到 vitality-controls.dll
目標文件,需要設置兩個項目之間的引用關系。
右鍵點擊 vicapp
項目,點擊快捷菜單添加
->引用
,彈出添加引用
對話框,如下:
p. 運行程序
點擊Visual Studio
的本地 Windows 調試器
按鈕,程序將啟動,並輸出 hello vic.
,如下:
至此,我們項目的基礎結構已經搭建完成。
下篇文章,我們將首先實現控件的初始化,以及控件展示功能,並討論一下我們之后的項目計划,敬請期待。
讓我們寫一個Win32文本編輯器吧
系列文章,其代碼對應項目vitality-controls
,主要對一個文本編輯器的實現過程進行說明。
如果要獲取到實時更新,歡迎微信掃描下方二維碼,關注微信公眾號編程之路漫漫
,碼途求知己,天涯覓一心。