问题
I'm trying to register a custom CodeInsight manager into C++Builder 10.1.2 Berlin.
Because there's nothing like Objects Pascal's initialization and finalization sections in C++, e.g.
var
codeManagerIndex: Integer;
{...}
initialization
codeManagerIndex := (BorlandIDEServices as IOTACodeInsightServices).AddCodeInsightManager(TMyCodeInsightManager.Create);
finalization
(borlandIDEServices as IOTACodeInsightServices).RemoveCodeInsightManager(codeManagerIndex);
end.
I tried reproducing their behavior with a custom runner class with constructor/destructor:
class Runner
{
public:
int FCodeManagerIndex;
_di_IOTACodeInsightServices CIS;
Runner() {
if (BorlandIDEServices->Supports(CIS))
FCodeManagerIndex = CIS->AddCodeInsightManager(new TMyCodeInsightManager);
}
~Runner() {
if (BorlandIDEServices->Supports(CIS))
CIS->RemoveCodeInsightManager(FCodeManagerIndex);
}
};
#pragma argsused
extern "C" int _libmain(unsigned long reason)
{
Runner Run;
return 1;
}
I can compile my simple implementation but when I try to install the package the following things are happening:
1st try: Error message: Can't load package ... mypackage.bpl - A dynamic link library (DLL) initialization routine failed.
2nd try: An exception (C0000005) occured during DllEntryPoint or DllMain in module: ... mypackage.bpl ... then the IDE crashes.
Is this a wrong way to register? What am I doing wrong here?
P.S. I get a [TLIB Warning] Warning: library was too large for page size, rebuilt with page size 32 warning when compiling, but I'm quite sure that this can't be the reason for my errors. (?)
回答1:
there's nothing like Objects Pascal's
initializationandfinalizationsections in C++
Actually, there is. In C++Builder, you can use #pragma startup and #pragma exit to execute user-defined functions:
static int FCodeManagerIndex = -1;
void DoRegister() {
_di_IOTACodeInsightServices CIS;
if (BorlandIDEServices->Supports(CIS)) {
FCodeManagerIndex = CIS->AddCodeInsightManager(new TMyCodeInsightManager);
}
}
#pragma startup DoRegister
void DoUnregister() {
_di_IOTACodeInsightServices CIS;
if ((FCodeManagerIndex != -1) && BorlandIDEServices->Supports(CIS)) {
CIS->RemoveCodeInsightManager(FCodeManagerIndex);
}
}
#pragma exit DoUnregister
#pragma argsused
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
Alternatively, since you ready declared a class to handle your registration, you can simply move your class variable into global static memory so its constructor runs at startup and destructor runs at shutdown:
class Runner
{
public:
int FCodeManagerIndex;
Runner() : FCodeManagerIndex(-1) {
_di_IOTACodeInsightServices CIS;
if (BorlandIDEServices->Supports(CIS)) {
FCodeManagerIndex = CIS->AddCodeInsightManager(new TMyCodeInsightManager);
}
}
~Runner() {
_di_IOTACodeInsightServices CIS;
if ((FCodeManagerIndex != -1) && BorlandIDEServices->Supports(CIS)) {
CIS->RemoveCodeInsightManager(FCodeManagerIndex);
}
}
};
static Runner Run;
#pragma argsused
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
Declaring the class variable inside of _libmain() is useless since the destructor will be called when the variable goes out of scope when _libmain() exits, thus unregistering the manager immediately after registering it. So the variable has to survive for as long as the package is loaded in memory.
来源:https://stackoverflow.com/questions/41922887/registering-a-custom-codeinsight-manager-to-cbuilder-without-initialization-fi