讓我們寫一個 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,主要對一個文本編輯器的實現過程進行說明。
如果要獲取到實時更新,歡迎微信掃描下方二維碼,關注微信公眾號編程之路漫漫,碼途求知己,天涯覓一心。

