首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

BCB ToolsAPI 實戰:打造自訂 IDE 擴充套件 (含中文化選單範例)

     編輯:關於C++

前言

Borland C++ Builder (BCB) 的 OpenTools API (ToolsAPI) 允許開發者編寫設計時套件,深度客製化 IDE 行為:新增選單項目、工具列、編輯器增強、專案向導、程式碼產生器等。本文以 BCB 5.0 為例,示範如何建立一個 BPL 設計時套件,載入時自動將主選單中文化,並提供完整的選單名稱對照表 (INI 格式) 供直接套用。

專案建立步驟

  1. File → New → Package 建立新套件專案 (.bpk)。
  2. 專案選項 → Requires 加入 vcl50.bpi, vcldb50.bpi, vclie50.bpi 等核心設計時套件。
  3. 專案選項 → Directories/Conditionals → Unit output directory 設為 $(BCB)\Bin (或自訂路徑)。
  4. 新增單元 (.cpp),撰寫註冊入口點 Register()。
  5. 編譯產生 .bpl,複製到 $(BCB)\Bin,IDE 下次啟動自動載入。

核心程式碼架構

#include <vcl.h>
#include <toolsapi.hpp>   // ToolsAPI 核心介面
#include <inifiles.hpp>   // TIniFile
#pragma hdrstop
#pragma package(smart_init)

namespace Nodebug
{
    // 設定旗標
    bool NeedLocalize = true;      // 是否套用中文化
    bool NeedWriteToIni = false;   // 是否匯出目前選單結構到 INI

    TIniFile *ini = nullptr;       // 匯出用 INI
    TIniFile *chsini = nullptr;    // 中文化對照表 (BCBCHS.INI)

    AnsiString Section, Ident, Value;

    //---------------------------------------------------------------------------
    // 遞迴列舉選單項目,可選擇匯出或套用標題
    //---------------------------------------------------------------------------
    void __fastcall DoMenuItem(TMenuItem* MenuItem)
    {
        if (!MenuItem) return;
        if (MenuItem->Visible == false) MenuItem->Visible = true; // 顯示隱藏項

        if (NeedWriteToIni && !MenuItem->Name.IsEmpty()) {
            Ident = MenuItem->Name;
            Value = MenuItem->Caption;
            ini->WriteString(Section, Ident, Value);
        }
    }

    void __fastcall EnumerateMenuItem(TMenuItem* MenuItem)
    {
        DoMenuItem(MenuItem);
        for (int i = 0; i < MenuItem->Count; ++i)
            EnumerateMenuItem(MenuItem->Items[i]);
    }

    //---------------------------------------------------------------------------
    // 從 CHS.INI 讀取對照表,套用中文化標題
    //---------------------------------------------------------------------------
    void __fastcall LocalizeAppMenu()
    {
        _di_INTAServices IDE;
        if (FAILED(BorlandIDEServices->QueryInterface(__uuidof(INTAServices), (void**)&IDE)))
            return;

        // 取得 IDE 主視窗 (TAppBuilder)
        TComponent* AppBuilder = IDE->MainMenu->Owner;

        TStringList* SectionList = new TStringList;
        TStringList* IdentList   = new TStringList;
        AnsiString Value;
        const AnsiString Default = "NULL";

        try {
            chsini->ReadSections(SectionList);
            for (int i = 0; i < SectionList->Count; ++i) {
                chsini->ReadSection(SectionList->Strings[i], IdentList);
                for (int x = 0; x < IdentList->Count; ++x) {
                    Value = chsini->ReadString(SectionList->Strings[i],
                                               IdentList->Strings[x], Default);
                    if (Value != Default) {
                        TMenuItem* MI = dynamic_cast<TMenuItem*>(
                            AppBuilder->FindComponent(IdentList->Strings[x]));
                        if (MI) MI->Caption = Value;
                    }
                }
            }
        }
        __finally {
            delete IdentList;
            delete SectionList;
        }
    }

    //---------------------------------------------------------------------------
    // 設計時套件進入點:IDE 載入 BPL 時自動呼叫
    //---------------------------------------------------------------------------
    void __fastcall PACKAGE Register()
    {
        // 開啟 INI 檔 (與 BPL 同目錄)
        ini   = new TIniFile(ChangeFileExt(Application->ExeName, ".INI"));
        chsini = new TIniFile(ChangeFileExt(Application->ExeName, "CHS.INI"));

        if (NeedLocalize) LocalizeAppMenu();

        _di_INTAServices IDE;
        if (FAILED(BorlandIDEServices->QueryInterface(__uuidof(INTAServices), (void**)&IDE))) {
            ShowMessage("無法存取 IDE 服務,請卸載此模組。");
            delete ini; delete chsini; return;
        }

        TComponent* AppBuilder = IDE->MainMenu->Owner;

        if (NeedWriteToIni) {
            // 匯出目前所有主選單結構到 INI,供製作翻譯表參考
            for (int i = 0; i < AppBuilder->ComponentCount; ++i) {
                if (AppBuilder->Components[i]->ClassNameIs("TMainMenu")) {
                    TMainMenu* MainMenu = dynamic_cast<TMainMenu*>(AppBuilder->Components[i]);
                    for (int x = 0; x < MainMenu->Items->Count; ++x) {
                        Section = MainMenu->Items->Items[x]->Name; // 頂層選單名稱作 Section
                        EnumerateMenuItem(MainMenu->Items->Items[x]);
                    }
                }
            }
        }

        delete ini;
        delete chsini;
    }
} // namespace

// DLL 進入點 (BPL 實為 DLL)
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
    return 1;
}

中文化對照表 (BCBCHS.INI)

將下列內容儲存為 $(BCB)\Bin\BCBCHS.INI (與 BPL 同目錄),設定 NeedLocalize=true 重啟 IDE 即可生效。

[FileMenu]
FileMenu=檔案(&F)
FileNewItem=新增(&N)...
FileNewApplicationItem=新增應用程式
FileNewFormItem=新增表單(&F)
FileNewUnitItem=新增單元(&U)
FileNewFrameItem=新增框架(&M)
FileOpenSeparater=-
FileOpenItem=開啟舊檔(&O)...
FileOpenProjectItem=開啟專案(&J)...
FileClosedFilesItem=重新開啟(&R)
FileSaveSeparater=-
FileSaveItem=儲存(&S)
FileSaveAsItem=另存新檔(&A)...
FileSaveProjectAs=專案另存新檔(&E)...
FileSaveAllItem=全部儲存(&V)
FileCloseItem=關閉(&C)
FileCloseAllItem=全部關閉(&L)
FileMenuSeparator=-
FileUseUnitItem=使用單元(&U)...
FilePrintItem=列印(&P)...
FileExitItem=結束(&X)

[EditMenu]
EditMenu=編輯(&E)
EditUndoItem=復原(&U)
EditRedoItem=取消復原(&R)
EditCutItem=剪下(&T)
EditCopyItem=複製(&C)
EditPasteItem=貼上(&P)
EditDeleteItem=刪除(&D)
EditSelectAll=全選(&A)
EditAlignGridItem=對齊格線(&G)
EditFrontItem=移至最上層(&F)
EditBackItem=移至最下層(&B)
EditAlignItem=對齊(&A)...
EditSizeItem=大小(&S)...
EditScaleItem=縮放(&E)...
EditTabOrderItem=Tab 順序(&O)...
EditCreationOrderItem=建立順序(&N)...
EditFlipChildrenItem=反轉子控制項(&H)
EditFlipChildrenAllItem=全部(&A)
EditFlipChildrenSelectedItem=選取項目(&S)
EditLockControlsItem=鎖定控制項(&K)
CORBAEditSeparator=-

[SearchMenu]
SearchMenu=搜尋(&S)
SearchFindItem=尋找(&F)...
SearchFileFindItem=在檔案中尋找(&D)...
SearchReplaceItem=取代(&R)...
SearchAgainItem=重複尋找(&S)
SearchIncrementalItem=漸進式搜尋(&I)
SearchGoToItem=移至指定行(&G)...
SearchGotoAddressItem=移至指定位址(&E)

[ViewsMenu]
ViewsMenu=檢視(&V)
ViewPrjMgrItem=專案管理器(&P)
TransMgrMenu=翻譯管理器(&M)
ViewObjInspItem=物件檢查器(&O)
ViewToDoListItem=待辦事項清單(&L)
ViewAlignItem=對齊面板(&A)
CodeExplorer=類別瀏覽器(&X)
ViewCompListItem=元件清單(&C)
ViewWindowListItem=視窗清單(&W)...
ViewDebugItem=偵錯視窗(&D)
ViewBreakpointsItem=中斷點(&B)
ViewCallStackItem=呼叫堆疊(&S)
ViewWatchesItem=監看式(&W)
ViewLocalVariablesItem=區域變數(&L)
ViewThreadsItem=執行緒(&T)
ViewModulesItem=模組(&M)
ViewEventLogItem=事件記錄(&E)
ViewCodeGuardLogItem=CodeGuard 記錄
ViewCPUItem=CPU 視窗(&C)
ViewFPUItem=FPU 視窗(&F)
ViewDesktopsMenu=桌面(&K)
SaveDesktop1=儲存桌面(&S)...
DeleteDesktop=刪除桌面(&T)...
SetDebugDesktop1=設定偵錯桌面(&D)
ViewToggleFormItem=切換表單/單元(&G)
ViewUnitItem=單元(&U)...
ViewFormItem=表單(&F)...
ViewTypeLibraryItem=類型程式庫(&T)
ViewNewEditorItem=新增編輯視窗(&E)
ViewToolbarsItem=工具列(&R)
ViewSwapSourceFormItem=切換原始碼/表單(&V)
ViewNextWindowItem=下一個視窗(隱藏)

[ProjectMenu]
ProjectMenu=專案(&P)
ProjectAddItem=加入檔案(&A)...
ProjectRemoveItem=從專案移除(&R)...
ProjectImportTypeLibraryItem=匯入類型程式庫(&L)...
ProjectAddRepositoryItem=加入物件庫(&T)...
ViewPrjSourceItem=檢視專案原始碼(&V)
InternationalMenu=語言(&G)
AddLangMenu=新增(&A)...
RemoveLangMenu=移除(&R)...
SetActiveLangMenu=設定啟用語言(&S)... (<無>)
UpdateResDLLMenu=更新資源 DLL(&U)
ProjectViewMakefileItem=檢視編譯選項原始檔(&P)
ProjectExportMakefileItem=匯出 Makefile...
N2=-
ProjectAddNewProjectItem=加入新專案(&N)...
ProjectAddExistingProjectItem=加入現有專案(&X)...
ProjectCompileSeparator=-
ProjectCompileUnitItem=編譯單元(&C)
ProjectCompileItem=&Make
ProjectBuildItem=&Build
ProjectInformationItem=專案資訊(&I)
N1=-
ProjectCompileAllItem=Make 所有專案(&K)
ProjectBuildAllItem=Build 所有專案(&U)
ProjectSeparator=-
ProjectDepOptItem=Web 部署選項(&W)...
ProjectDeployItem=Web 部署(&D)
ProjectSeparator2=-
ProjectOptionsItem=選項(&O)...

[RunMenu]
RunMenu=執行(&R)
RunRunItem=執行(&R)
RunAttachtoProcessItem=附加至處理序(&O)...
RunParametersItem=參數(&P)...
RunRegisterComItem=註冊 ActiveX 伺服器(&A)
RunUnregisterComItem=註銷 ActiveX 伺服器(&X)
RunParametersSeparator=-
RunStepOverItem=逐步執行(&S)
RunTraceIntoItem=追蹤進入(&T)
RunTraceToSourceItem=追蹤至下一行原始碼(&N)
RunGotoCursorItem=執行至游標處(&C)
RunUntilReturnItem=執行至函式返回(&U)
RunShowCSIPItem=顯示執行點(&H)
RunPauseItem=暫停程式(&P)
RunResetItem=重置程式(&R)
RunInspectSeparator=-
RunInspectItem=巡檢(&I)...
RunEvalModItem=運算/修改(&E)...
RunAddWatchItem=加入監看式(&W)...
RunAddBreakItem=加入中斷點(&B)
RunAddSourceBreakpointItem=原始碼中斷點(&S)...
RunAddAddressBreakpointItem=位址中斷點(&A)...
RunAddDataBreakpointItem=資料中斷點(&D)...
RunAddModuleLoadBreakpointItem=模組載入中斷點(&M)...

[ComponentMenu]
ComponentMenu=元件(&C)
ComponentNewItem=新增元件(&N)...
ComponentAddtoPackage=安裝元件(&I)...
ComponentImportAXCItem=匯入 ActiveX 控制項(&X)...
ComponentInstallCompositeItem=建立元件範本(&T)...
ComponentInstallPackagesItem=安裝套件(&P)...
ComponentPaletteItem=設定調色盤(&C)...

[DatabaseMenu]
DatabaseMenu=資料庫(&D)
Borland_DbExplorerItem=瀏覽器(&E)
Borland_SQLMonitorItem=SQL 監視器(&S)
Borland_FormWizardItem=表單精靈(&F)...

[ToolsMenu]
ToolsMenu=工具(&T)
ToolsOptionsItem=環境選項(&O)...
ToolsEditorOptionsItem=編輯器選項(&E)...
ToolsDebuggerOptionsItem=偵錯器選項(&D)...
ITEOptionsMenu=翻譯工具選項(&N)...
ToolsGalleryItem=物件庫(&R)...
RepositoryMenu=翻譯物件庫(&A)...
CORBAToolsSeparator1=-
CORBAToolsSeparator2=-
ToolsToolsItem=設定外部工具(&T)...

[HelpMenu]
HelpMenu=說明(&H)
HelpContentsItem=C++Builder 說明
HelpCBuilderToolsItem=C++Builder 工具(&T)
HelpWinSDKItem=Windows SDK(&W)
HelpInprisePage=Borland 首頁(&B)
HelpCommunityPage=Borland 論壇
HelpCBuilderPage=C++Builder 首頁(&P)
HelpDevSupportPage=開發人員支援(&S)
DirectItem=C++Builder 直通車(&R)...
HelpProgGuideSeparater=-
HelpCustomizeItem=自訂(&T)...
HelpAboutSeparator=-
HelpAboutItem=關於(&A)...

已知問題與解決

  • 資料庫選單無效:BCB 5 的資料庫選單為動態建立,Register() 執行時尚未存在。解決:在 Register() 中註冊 INTAEditorServices 的 OnMenuAction 事件,或使用 TTimer 延遲套用。
  • BPL 載入順序:若有多個設計時套件修改選單,順序可能影響結果。調整 Registry\Known IDE Packages 中的載入順序。
  • BCB 6/2007 以上:介面 GUID 可能變更,需依對應版本 toolsapi.hpp 調整。

延伸應用

  • 新增自訂選單項目:INTAServices->MainMenu->Items->Add(...) 並掛載 _di_IOTAMenuWizard 實作執行動作。
  • 編輯器增強:實作 IOTAEditorWizard、IOTAKeyBinding 等介面。
  • 專案向導:實作 IOTAWizard、IOTARepositoryWizard。
  • 程式碼產生/重構:實作 IOTACodeGenerator。

參考資源

  • BCB 線上說明:OpenTools API Reference
  • $(BCB)\Source\ToolsAPI\ 範例專案
  • 《Borland C++ Builder 5 Developer's Guide》第 24 章:Creating Design-Time Packages
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved