讓我們寫一個 Win32 文本編輯器吧 - 1. 簡介

讓我們寫一個 Win32 文本編輯器吧 - 1. 簡介

在之前的一篇文章 《曾經我認為C語言就是個弟弟》 中,我們通過使用 Windows 系統自帶的 EDIT 控制項,創建了一個簡單的文本編輯器。而且在文章的最後,還承諾要不使用 EDIT 控制項,自己製作一個十六進位編輯器。

後來想到,既然十六進位編輯器都做了,作為一個程式設計師,不如寫一個文本編輯器吧,既可以編輯二進位,又可以編輯文本,豈不美哉。

由於實現一個編輯器的複雜性相對比較大,一篇內容肯定完不成。所以,這裡決定將整個過程作為一個系列來編輯。

本篇是系列的第一篇。在本篇文章中,將會對我們期望獲得的結果進行簡單的描述,並進行基礎程式碼框架進行構建。

本文主要包含兩個部分,如下:

  1. 項目簡介

在項目簡介部分,將會對我們要實現的目標編輯器的樣子,以及使用方法進行介紹。同時,也會對本系列接下來的文章要討論的主題進行大致說明。

  1. 基礎程式碼框架搭建

在程式碼框架搭建部分,將會對項目的創建,設置進行說明。並編輯我們的基礎程式碼。

1. 項目簡介

a. 目標

在 Windows11 中,已經將記事本的編輯控制項由 EDIT 替換為 RichEditD2DPT,詳情參考Windows 11 Notepad。但是由於關於 RichEditD2DPT 控制項的描述太少,不知道其具體的用方法。
所以,這裡我們以 EDIT 控制項的介面為準,並實現附加功能。

在此,我們的目標是:通過 C 語言,調用 Win32 介面,生成一個文本編輯器。目標編輯器除了實現和 Windows 提供的默認文本編輯器 EDIT 的所有消息處理,還提供如下功能:

  1. 可以設置字體顏色

    對於 EDIT 控制項,雖然可以設置其文本字體,但是沒有設置顏色的方法。

  2. 可以編輯比較大的文件

    對於平時的文件編輯器來說,編輯小文件基本上都差不多,但是當遇到比較大的文件時(比如1G),很可能無能為力,甚至卡死。
    所以,既然我們要做一個新的編輯器,自然要考慮大文件的編輯問題。

  3. 採取Direct Write方式實現,而不是和普通的編輯器一樣,通過 GDI。

    做此選擇的原因,除了因為 Direct Write 支援顏色之外,還有一些其它優點,詳情可以點擊Direct Write進行參考。

  4. 支援 EDIT控制項 的所有消息。

    為了使得舊 Win32 程式碼更好的使用本編輯器,所有 EDIT 控制項支援的操作,本項目都應該支援。

  5. 處理\r\n

    此選擇和Windows 11中的選擇具有相同的理由,為了更好的處理換行。

  6. 支援撤銷操作/恢復上一步操作

    在編輯文本時,難免會想恢復到不久之前的版本,撤銷操作允許你做到這個。而當你後悔撤銷的時候,也應該能夠恢復到最新版本,恢復上一步允許你做到重新執行你之前的操作。

  7. 支援 Unicode 編碼

  8. 可以設置註解

    在編輯時,尤其是要編輯二進位文件時,我們有時候可能要對某個位元組,或某段文本進行註解。我們的編輯器允許提供一個註解結構,以在顯示文檔時,可以進行註解顯示。

  9. 可以進行二進位文件編輯。

    二進位編輯雖然不常用,但是,不能在需要用的時候找不到。所以,這裡提供了二進位編輯功能。此功能和註解相結合,就可以進行輔助二進位文件的分析。

b. 目標編輯器的樣子

作為一個現代的編輯器,我們希望它有一般編輯器都應該有的能力,下面是一個編輯器的例子:
![](//img2022.cnblogs.com/blog/456172/202204/456172-20220403204453442-1758134648.png)

不難看到,作為一個編輯器,應該支援行號,高亮,多字體,滾動條等內容。這在我們的編輯器中,都將一一實現,並詳細描述實現過程。

c. 項目結構

對於本項目來說,一共包含兩個子項目,如下:

  • vicapp:
    用於對編輯器控制項進行調用的樣常式序
  • vitality-controls:
    編輯器控制項的實現項目,將作為一個 DLL 文件提供給調用者。

d. 參考鏈接

程式碼地址://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,主要對一個文本編輯器的實現過程進行說明。

如果要獲取到實時更新,歡迎微信掃描下方二維碼,關注微信公眾號編程之路漫漫,碼途求知己,天涯覓一心。