Borland C++ Builder (BCB) 的 OpenTools API (ToolsAPI) 允許開發者編寫設計時套件,深度客製化 IDE 行為:新增選單項目、工具列、編輯器增強、專案向導、程式碼產生器等。本文以 BCB 5.0 為例,示範如何建立一個 BPL 設計時套件,載入時自動將主選單中文化,並提供完整的選單名稱對照表 (INI 格式) 供直接套用。
.bpk)。vcl50.bpi, vcldb50.bpi, vclie50.bpi 等核心設計時套件。$(BCB)\Bin (或自訂路徑)。.cpp),撰寫註冊入口點 Register()。.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;
}
將下列內容儲存為 $(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)...
Register() 執行時尚未存在。解決:在 Register() 中註冊 INTAEditorServices 的 OnMenuAction 事件,或使用 TTimer 延遲套用。Registry\Known IDE Packages 中的載入順序。toolsapi.hpp 調整。INTAServices->MainMenu->Items->Add(...) 並掛載 _di_IOTAMenuWizard 實作執行動作。IOTAEditorWizard、IOTAKeyBinding 等介面。IOTAWizard、IOTARepositoryWizard。IOTACodeGenerator。$(BCB)\Source\ToolsAPI\ 範例專案