-
Notifications
You must be signed in to change notification settings - Fork 63
/
DN.ExpertService.pas
195 lines (178 loc) · 4.21 KB
/
DN.ExpertService.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
unit DN.ExpertService;
interface
uses
DN.ExpertService.Intf;
type
TDNExpertService = class(TInterfacedObject, IDNExpertService)
private
FRootKey: string;
public
constructor Create(const ARootKey: string);
function RegisterExpert(const AExpert: string; ALoad: Boolean = False): Boolean;
function UnregisterExpert(const AExpert: string; AUnload: Boolean = False): Boolean;
end;
procedure LoadExpert(const AExpert: string);
procedure UnloadExpert(const AExpert: string);
implementation
uses
Classes,
Types,
Windows,
SysUtils,
StrUtils,
RTTI,
IniFiles,
Registry;
function TryGetExpertService(out AService: TObject): Boolean;
var
LLibName: string;
LContext: TRttiContext;
LPackage: TRttiPackage;
LService: ^TObject;
const
CExpertServiceSymbol = '@Exptmain@ExpertServices';
begin
Result := False;
for LPackage in LContext.GetPackages() do
begin
LLibName := ExtractFileName(LPackage.Name);
if StartsText('CoreIDE', LLibName) and EndsText('.bpl', LLibName) then
begin
LService := GetProcAddress(LPackage.Handle, CExpertServiceSymbol);
if Assigned(LService) then
begin
AService := LService^;
Exit(True);
end;
end;
end;
end;
function TryGetExtertLibName(AExpert: TObject; out ALibName: string): Boolean;
var
LContext: TRttiContext;
LType: TRTTIType;
LField: TRttiField;
begin
Result := False;
LType := LContext.GetType(AExpert.ClassType);
LField := LType.GetField('LibHandle');
if Assigned(LField) then
begin
ALibName := GetModuleName(NativeUInt(LField.GetValue(AExpert).AsInt64));
Result := True;
end;
end;
procedure LoadExpert(const AExpert: string);
var
LService: TObject;
LRTTI: TRttiContext;
LType: TRttiType;
LMethod: TRttiMethod;
const
CLoadExpertLib = 'LoadExpertLib';
begin
if TryGetExpertService(LService) then
begin
LType := LRTTI.GetType(LService.ClassType);
LMethod := LType.GetMethod(CLoadExpertLib);
if Assigned(LMethod) then
begin
try
LMethod.Invoke(LService, [AExpert]);
except
end;
end;
end;
end;
procedure UnloadExpert(const AExpert: string);
var
LService: TObject;
LRTTI: TRttiContext;
LType: TRttiType;
LList: TList;
LUnload: TRttiMethod;
LField: TRttiField;
LExpert: Pointer;
LExpertLib: string;
const
CLibList = 'LibList';
CUnloadExpertLib = 'UnloadExpertLib';
begin
if TryGetExpertService(LService) then
begin
LType := LRTTI.GetType(LService.ClassType);
LField := LType.GetField(CLibList);
LUnload := LType.GetMethod(CUnloadExpertLib);
if Assigned(LField) then
begin
LList := TList(LField.GetValue(LService).AsObject);
if Assigned(LList) then
begin
for LExpert in LList do
begin
if TryGetExtertLibName(TObject(LExpert), LExpertLib) and SameText(AExpert, LExpertLib) then
begin
try
LUnload.Invoke(LService, [TObject(LExpert)]);
except
end;
Break;
end;
end;
end;
end;
end;
end;
{ TDNExpertService }
constructor TDNExpertService.Create(const ARootKey: string);
var
LService: TObject;
begin
inherited Create();
FRootKey := ARootKey;
TryGetExpertService(LService);
end;
function TDNExpertService.RegisterExpert(const AExpert: string;
ALoad: Boolean): Boolean;
var
LRegistry: TRegistry;
begin
Result := False;
LRegistry := TRegistry.Create();
try
if LRegistry.OpenKey(FRootKey, False) then
begin
if LRegistry.OpenKey('Experts', True) then
begin
LRegistry.WriteString(ExtractFileName(AExpert), AExpert);
if ALoad then
LoadExpert(AExpert);
Result := True;
end;
end;
finally
LRegistry.Free;
end;
end;
function TDNExpertService.UnregisterExpert(const AExpert: string;
AUnload: Boolean): Boolean;
var
LRegistry: TRegistry;
begin
Result := False;
LRegistry := TRegistry.Create();
try
if LRegistry.OpenKey(FRootKey, False) then
begin
if LRegistry.OpenKey('Experts', True) then
begin
Result := LRegistry.DeleteValue(ExtractFileName(AExpert));
if AUnload then
UnloadExpert(AExpert);
end;
end;
finally
LRegistry.Free;
end;
end;
end.