Rev 81 | Rev 83 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
68 | daniel-mar | 1 | unit UD2_Obj; |
2 | |||
3 | interface |
||
4 | |||
5 | {$IF CompilerVersion >= 25.0} |
||
6 | {$LEGACYIFEND ON} |
||
7 | {$IFEND} |
||
8 | |||
70 | daniel-mar | 9 | {$INCLUDE 'UserDetect2.inc'} |
10 | |||
68 | daniel-mar | 11 | uses |
71 | daniel-mar | 12 | Windows, SysUtils, Classes, IniFiles, Contnrs, Dialogs, UD2_PluginIntf, |
13 | UD2_PluginStatus; |
||
68 | daniel-mar | 14 | |
15 | const |
||
69 | daniel-mar | 16 | cchBufferSize = 32768; |
68 | daniel-mar | 17 | |
18 | type |
||
19 | TUD2Plugin = class(TObject) |
||
20 | protected |
||
21 | FDetectedIdentifications: TObjectList{<TUD2IdentificationEntry>}; |
||
22 | public |
||
82 | daniel-mar | 23 | // This flag will be set if "AutoOSNotSupportedCompatibility" of the INI manifest had to be enforced/used |
24 | OSNotSupportedEnforced: boolean; |
||
25 | |||
68 | daniel-mar | 26 | PluginDLL: string; |
27 | PluginGUID: TGUID; |
||
28 | PluginName: WideString; |
||
29 | PluginVendor: WideString; |
||
30 | PluginVersion: WideString; |
||
31 | IdentificationMethodName: WideString; |
||
70 | daniel-mar | 32 | |
33 | // ONLY contains the non-failure status code of IdentificationStringW |
||
34 | IdentificationProcedureStatusCode: UD2_STATUS; |
||
35 | IdentificationProcedureStatusCodeDescribed: WideString; |
||
36 | |||
69 | daniel-mar | 37 | Time: Cardinal; |
68 | daniel-mar | 38 | function PluginGUIDString: string; |
39 | property DetectedIdentifications: TObjectList{<TUD2IdentificationEntry>} |
||
40 | read FDetectedIdentifications; |
||
41 | destructor Destroy; override; |
||
42 | constructor Create; |
||
43 | procedure AddIdentification(IdStr: WideString); |
||
44 | end; |
||
45 | |||
46 | TUD2IdentificationEntry = class(TObject) |
||
47 | private |
||
48 | FIdentificationString: WideString; |
||
49 | FPlugin: TUD2Plugin; |
||
50 | public |
||
51 | property IdentificationString: WideString read FIdentificationString; |
||
52 | property Plugin: TUD2Plugin read FPlugin; |
||
53 | function GetPrimaryIdName: WideString; |
||
54 | procedure GetIdNames(sl: TStrings); |
||
55 | constructor Create(AIdentificationString: WideString; APlugin: TUD2Plugin); |
||
56 | end; |
||
57 | |||
58 | TUD2 = class(TObject) |
||
59 | private |
||
70 | daniel-mar | 60 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
68 | daniel-mar | 61 | FGUIDLookup: TStrings; |
70 | daniel-mar | 62 | {$ENDIF} |
68 | daniel-mar | 63 | protected |
64 | FLoadedPlugins: TObjectList{<TUD2Plugin>}; |
||
65 | FIniFile: TMemIniFile; |
||
66 | FErrors: TStrings; |
||
67 | FIniFileName: string; |
||
68 | public |
||
69 | property IniFileName: string read FIniFileName; |
||
70 | property Errors: TStrings read FErrors; |
||
71 | property LoadedPlugins: TObjectList{<TUD2Plugin>} read FLoadedPlugins; |
||
72 | property IniFile: TMemIniFile read FIniFile; |
||
82 | daniel-mar | 73 | procedure GetAllIdNames(outSL: TStrings); |
74 | function FulfilsEverySubterm(idTerm: WideString; slIdNames: TStrings=nil): boolean; |
||
68 | daniel-mar | 75 | procedure GetCommandList(ShortTaskName: string; outSL: TStrings); |
80 | daniel-mar | 76 | procedure HandlePluginDir(APluginDir, AFileMask: string); |
68 | daniel-mar | 77 | procedure GetTaskListing(outSL: TStrings); |
78 | constructor Create(AIniFileName: string); |
||
79 | destructor Destroy; override; |
||
80 | function TaskExists(ShortTaskName: string): boolean; |
||
80 | daniel-mar | 81 | function ReadMetatagString(ShortTaskName, MetatagName: string; DefaultVal: string): string; |
82 | function ReadMetatagBool(ShortTaskName, MetatagName: string; DefaultVal: string): boolean; |
||
68 | daniel-mar | 83 | function GetTaskName(AShortTaskName: string): string; |
71 | daniel-mar | 84 | class function GenericErrorLookup(grStatus: UD2_STATUS): string; |
68 | daniel-mar | 85 | end; |
86 | |||
87 | implementation |
||
88 | |||
89 | uses |
||
70 | daniel-mar | 90 | UD2_Utils; |
68 | daniel-mar | 91 | |
69 | daniel-mar | 92 | type |
93 | TUD2PluginLoader = class(TThread) |
||
94 | protected |
||
95 | dllFile: string; |
||
96 | lngID: LANGID; |
||
97 | procedure Execute; override; |
||
70 | daniel-mar | 98 | function HandleDLL: boolean; |
69 | daniel-mar | 99 | public |
100 | pl: TUD2Plugin; |
||
101 | Errors: TStringList; |
||
102 | constructor Create(Suspended: boolean; DLL: string; alngid: LANGID); |
||
103 | destructor Destroy; override; |
||
104 | end; |
||
105 | |||
71 | daniel-mar | 106 | class function TUD2.GenericErrorLookup(grStatus: UD2_STATUS): string; |
68 | daniel-mar | 107 | resourcestring |
80 | daniel-mar | 108 | LNG_STATUS_OK_UNSPECIFIED = 'Success (Unspecified)'; |
109 | LNG_STATUS_OK_SINGLELINE = 'Success (One identifier returned)'; |
||
110 | LNG_STATUS_OK_MULTILINE = 'Success (Multiple identifiers returned)'; |
||
111 | LNG_UNKNOWN_SUCCESS = 'Success (Unknown status code %s)'; |
||
69 | daniel-mar | 112 | |
80 | daniel-mar | 113 | LNG_STATUS_NOTAVAIL_UNSPECIFIED = 'Not available (Unspecified)'; |
114 | LNG_STATUS_NOTAVAIL_OS_NOT_SUPPORTED = 'Not available (Operating system not supported)'; |
||
115 | LNG_STATUS_NOTAVAIL_HW_NOT_SUPPORTED = 'Not available (Hardware not supported)'; |
||
116 | LNG_STATUS_NOTAVAIL_NO_ENTITIES = 'Not available (No entities to identify)'; |
||
117 | LNG_STATUS_NOTAVAIL_WINAPI_CALL_FAILURE = 'Not available (A Windows API call failed. Message: %s)'; |
||
118 | LNG_UNKNOWN_NOTAVAIL = 'Not available (Unknown status code %s)'; |
||
69 | daniel-mar | 119 | |
82 | daniel-mar | 120 | LNG_STATUS_FAILURE_UNSPECIFIED = 'Error (Unspecified)'; |
121 | LNG_STATUS_FAILURE_BUFFER_TOO_SMALL = 'Error (The provided buffer is too small!)'; |
||
122 | LNG_STATUS_FAILURE_INVALID_ARGS = 'Error (The function received invalid arguments!)'; |
||
123 | LNG_STATUS_FAILURE_PLUGIN_NOT_LICENSED = 'Error (The plugin is not licensed)'; |
||
124 | LNG_STATUS_FAILURE_NO_RETURNED_VALUE = 'Error (Plugin did not return a status)'; |
||
125 | LNG_STATUS_FAILURE_CATCHED_EXCEPTION = 'Error (Catched unexpected Exception)'; |
||
80 | daniel-mar | 126 | LNG_UNKNOWN_FAILED = 'Error (Unknown status code %s)'; |
69 | daniel-mar | 127 | |
71 | daniel-mar | 128 | LNG_UNKNOWN_STATUS = 'Unknown status code with unexpected category: %s'; |
68 | daniel-mar | 129 | begin |
71 | daniel-mar | 130 | if UD2_STATUS_Equal(grStatus, UD2_STATUS_OK_UNSPECIFIED, false) then result := LNG_STATUS_OK_UNSPECIFIED |
131 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_OK_SINGLELINE, false) then result := LNG_STATUS_OK_SINGLELINE |
||
132 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_OK_MULTILINE, false) then result := LNG_STATUS_OK_MULTILINE |
||
69 | daniel-mar | 133 | |
71 | daniel-mar | 134 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_UNSPECIFIED, false) then result := LNG_STATUS_NOTAVAIL_UNSPECIFIED |
135 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_OS_NOT_SUPPORTED, false) then result := LNG_STATUS_NOTAVAIL_OS_NOT_SUPPORTED |
||
136 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_HW_NOT_SUPPORTED, false) then result := LNG_STATUS_NOTAVAIL_HW_NOT_SUPPORTED |
||
137 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_NO_ENTITIES, false) then result := LNG_STATUS_NOTAVAIL_NO_ENTITIES |
||
138 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_WINAPI_CALL_FAILURE, false) then result := Format(LNG_STATUS_NOTAVAIL_WINAPI_CALL_FAILURE, [FormatOSError(grStatus.dwExtraInfo)]) |
||
69 | daniel-mar | 139 | |
82 | daniel-mar | 140 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_UNSPECIFIED, false) then result := LNG_STATUS_FAILURE_UNSPECIFIED |
141 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_BUFFER_TOO_SMALL, false) then result := LNG_STATUS_FAILURE_BUFFER_TOO_SMALL |
||
142 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_INVALID_ARGS, false) then result := LNG_STATUS_FAILURE_INVALID_ARGS |
||
143 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_PLUGIN_NOT_LICENSED, false) then result := LNG_STATUS_FAILURE_PLUGIN_NOT_LICENSED |
||
144 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_NO_RETURNED_VALUE, false) then result := LNG_STATUS_FAILURE_NO_RETURNED_VALUE |
||
145 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_CATCHED_EXCEPTION, false) then result := LNG_STATUS_FAILURE_CATCHED_EXCEPTION |
||
69 | daniel-mar | 146 | |
71 | daniel-mar | 147 | else if grStatus.wCategory = UD2_STATUSCAT_SUCCESS then result := Format(LNG_UNKNOWN_SUCCESS, [UD2_STATUS_FormatStatusCode(grStatus)]) |
148 | else if grStatus.wCategory = UD2_STATUSCAT_NOT_AVAIL then result := Format(LNG_UNKNOWN_NOTAVAIL, [UD2_STATUS_FormatStatusCode(grStatus)]) |
||
149 | else if grStatus.wCategory = UD2_STATUSCAT_FAILED then result := Format(LNG_UNKNOWN_FAILED, [UD2_STATUS_FormatStatusCode(grStatus)]) |
||
150 | else result := Format(LNG_UNKNOWN_STATUS, [UD2_STATUS_FormatStatusCode(grStatus)]); |
||
68 | daniel-mar | 151 | end; |
152 | |||
153 | { TUD2Plugin } |
||
154 | |||
155 | function TUD2Plugin.PluginGUIDString: string; |
||
156 | begin |
||
157 | result := UpperCase(GUIDToString(PluginGUID)); |
||
158 | end; |
||
159 | |||
160 | procedure TUD2Plugin.AddIdentification(IdStr: WideString); |
||
161 | begin |
||
162 | DetectedIdentifications.Add(TUD2IdentificationEntry.Create(IdStr, Self)) |
||
163 | end; |
||
164 | |||
165 | destructor TUD2Plugin.Destroy; |
||
166 | begin |
||
167 | DetectedIdentifications.Free; |
||
168 | inherited; |
||
169 | end; |
||
170 | |||
171 | constructor TUD2Plugin.Create; |
||
172 | begin |
||
173 | inherited Create; |
||
174 | FDetectedIdentifications := TObjectList{<TUD2IdentificationEntry>}.Create(true); |
||
175 | end; |
||
176 | |||
177 | { TUD2IdentificationEntry } |
||
178 | |||
179 | function TUD2IdentificationEntry.GetPrimaryIdName: WideString; |
||
180 | begin |
||
181 | result := Plugin.IdentificationMethodName+':'+IdentificationString; |
||
182 | end; |
||
183 | |||
184 | procedure TUD2IdentificationEntry.GetIdNames(sl: TStrings); |
||
185 | begin |
||
186 | sl.Add(GetPrimaryIdName); |
||
82 | daniel-mar | 187 | sl.Add(Plugin.IdentificationMethodName+':'+IdentificationString); |
188 | sl.Add(Plugin.PluginGUIDString+':'+IdentificationString); |
||
68 | daniel-mar | 189 | end; |
190 | |||
191 | constructor TUD2IdentificationEntry.Create(AIdentificationString: WideString; |
||
192 | APlugin: TUD2Plugin); |
||
193 | begin |
||
194 | inherited Create; |
||
195 | FIdentificationString := AIdentificationString; |
||
196 | FPlugin := APlugin; |
||
197 | end; |
||
198 | |||
199 | { TUD2 } |
||
200 | |||
80 | daniel-mar | 201 | procedure TUD2.HandlePluginDir(APluginDir, AFileMask: string); |
69 | daniel-mar | 202 | Var |
203 | SR: TSearchRec; |
||
204 | path: string; |
||
70 | daniel-mar | 205 | pluginLoader: TUD2PluginLoader; |
69 | daniel-mar | 206 | tob: TObjectList; |
68 | daniel-mar | 207 | i: integer; |
70 | daniel-mar | 208 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
209 | sPluginID, prevDLL: string; |
||
210 | {$ENDIF} |
||
69 | daniel-mar | 211 | lngid: LANGID; |
68 | daniel-mar | 212 | resourcestring |
213 | LNG_PLUGINS_SAME_GUID = 'Attention: The plugin "%s" and the plugin "%s" have the same identification GUID. The latter will not be loaded.'; |
||
214 | begin |
||
69 | daniel-mar | 215 | tob := TObjectList.Create; |
68 | daniel-mar | 216 | try |
69 | daniel-mar | 217 | tob.OwnsObjects := false; |
68 | daniel-mar | 218 | |
69 | daniel-mar | 219 | lngID := GetSystemDefaultLangID; |
68 | daniel-mar | 220 | |
80 | daniel-mar | 221 | path := APluginDir; |
222 | if path <> '' then path := IncludeTrailingPathDelimiter(path); |
||
223 | |||
224 | if FindFirst(path + AFileMask, 0, SR) = 0 then |
||
68 | daniel-mar | 225 | begin |
226 | try |
||
69 | daniel-mar | 227 | repeat |
228 | try |
||
80 | daniel-mar | 229 | tob.Add(TUD2PluginLoader.Create(false, path + sr.Name, lngid)); |
69 | daniel-mar | 230 | except |
231 | on E: Exception do |
||
232 | begin |
||
233 | MessageDlg(E.Message, mtError, [mbOK], 0); |
||
234 | end; |
||
235 | end; |
||
236 | until FindNext(SR) <> 0; |
||
68 | daniel-mar | 237 | finally |
69 | daniel-mar | 238 | FindClose(SR); |
68 | daniel-mar | 239 | end; |
240 | end; |
||
241 | |||
69 | daniel-mar | 242 | for i := 0 to tob.count-1 do |
68 | daniel-mar | 243 | begin |
70 | daniel-mar | 244 | pluginLoader := tob.items[i] as TUD2PluginLoader; |
245 | pluginLoader.WaitFor; |
||
246 | Errors.AddStrings(pluginLoader.Errors); |
||
247 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
||
248 | if Assigned(pluginLoader.pl) then |
||
68 | daniel-mar | 249 | begin |
82 | daniel-mar | 250 | if not pluginLoader.pl.OSNotSupportedEnforced then |
69 | daniel-mar | 251 | begin |
82 | daniel-mar | 252 | sPluginID := GUIDToString(pluginLoader.pl.PluginGUID); |
253 | prevDLL := FGUIDLookup.Values[sPluginID]; |
||
254 | if (prevDLL <> '') and (prevDLL <> pluginLoader.pl.PluginDLL) then |
||
255 | begin |
||
256 | Errors.Add(Format(LNG_PLUGINS_SAME_GUID, [prevDLL, pluginLoader.pl.PluginDLL])); |
||
257 | pluginLoader.pl.Free; |
||
258 | end |
||
259 | else |
||
260 | begin |
||
261 | FGUIDLookup.Values[sPluginID] := pluginLoader.pl.PluginDLL; |
||
262 | LoadedPlugins.Add(pluginLoader.pl); |
||
263 | end; |
||
69 | daniel-mar | 264 | end; |
68 | daniel-mar | 265 | end; |
70 | daniel-mar | 266 | {$ENDIF} |
267 | pluginLoader.Free; |
||
68 | daniel-mar | 268 | end; |
269 | finally |
||
69 | daniel-mar | 270 | tob.free; |
68 | daniel-mar | 271 | end; |
272 | end; |
||
273 | |||
274 | destructor TUD2.Destroy; |
||
275 | begin |
||
276 | FIniFile.Free; |
||
277 | FLoadedPlugins.Free; |
||
70 | daniel-mar | 278 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
68 | daniel-mar | 279 | FGUIDLookup.Free; |
70 | daniel-mar | 280 | {$ENDIF} |
68 | daniel-mar | 281 | FErrors.Free; |
282 | end; |
||
283 | |||
284 | constructor TUD2.Create(AIniFileName: string); |
||
285 | begin |
||
286 | FIniFileName := AIniFileName; |
||
287 | FLoadedPlugins := TObjectList{<TUD2Plugin>}.Create(true); |
||
288 | FIniFile := TMemIniFile.Create(IniFileName); |
||
70 | daniel-mar | 289 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
68 | daniel-mar | 290 | FGUIDLookup := TStringList.Create; |
70 | daniel-mar | 291 | {$ENDIF} |
68 | daniel-mar | 292 | FErrors := TStringList.Create; |
293 | end; |
||
294 | |||
295 | function TUD2.GetTaskName(AShortTaskName: string): string; |
||
69 | daniel-mar | 296 | resourcestring |
297 | LNG_NO_DESCRIPTION = '(%s)'; |
||
68 | daniel-mar | 298 | begin |
69 | daniel-mar | 299 | result := FIniFile.ReadString(AShortTaskName, 'Description', Format(LNG_NO_DESCRIPTION, [AShortTaskName])); |
68 | daniel-mar | 300 | end; |
301 | |||
302 | procedure TUD2.GetTaskListing(outSL: TStrings); |
||
303 | var |
||
304 | sl: TStringList; |
||
305 | i: integer; |
||
306 | desc: string; |
||
307 | begin |
||
308 | sl := TStringList.Create; |
||
309 | try |
||
310 | FIniFile.ReadSections(sl); |
||
311 | for i := 0 to sl.Count-1 do |
||
312 | begin |
||
313 | desc := GetTaskName(sl.Strings[i]); |
||
314 | outSL.Values[sl.Strings[i]] := desc; |
||
315 | end; |
||
316 | finally |
||
317 | sl.Free; |
||
318 | end; |
||
319 | end; |
||
320 | |||
321 | function TUD2.TaskExists(ShortTaskName: string): boolean; |
||
322 | begin |
||
323 | result := FIniFile.SectionExists(ShortTaskName); |
||
324 | end; |
||
325 | |||
326 | function TUD2.ReadMetatagString(ShortTaskName, MetatagName: string; |
||
327 | DefaultVal: string): string; |
||
328 | begin |
||
329 | result := IniFile.ReadString(ShortTaskName, MetatagName, DefaultVal); |
||
330 | end; |
||
331 | |||
332 | function TUD2.ReadMetatagBool(ShortTaskName, MetatagName: string; |
||
333 | DefaultVal: string): boolean; |
||
334 | begin |
||
335 | // DefaultVal is a string, because we want to allow an empty string, in case the |
||
336 | // user wishes an Exception in case the string is not a valid boolean string |
||
337 | result := BetterInterpreteBool(IniFile.ReadString(ShortTaskName, MetatagName, DefaultVal)); |
||
338 | end; |
||
339 | |||
340 | (* |
||
341 | |||
342 | NAMING EXAMPLE: ComputerName:ABC&&User:John=calc.exe |
||
343 | |||
344 | idTerm: ComputerName:ABC&&User:John |
||
345 | idName: ComputerName:ABC |
||
346 | IdMethodName: ComputerName |
||
347 | IdStr ABC |
||
348 | cmd: calc.exe |
||
349 | |||
350 | *) |
||
351 | |||
81 | daniel-mar | 352 | procedure TUD2.GetAllIdNames(outSL: TStrings); |
68 | daniel-mar | 353 | var |
354 | i, j: integer; |
||
355 | pl: TUD2Plugin; |
||
356 | ude: TUD2IdentificationEntry; |
||
357 | begin |
||
81 | daniel-mar | 358 | for i := 0 to LoadedPlugins.Count-1 do |
359 | begin |
||
360 | pl := LoadedPlugins.Items[i] as TUD2Plugin; |
||
361 | for j := 0 to pl.DetectedIdentifications.Count-1 do |
||
362 | begin |
||
363 | ude := pl.DetectedIdentifications.Items[j] as TUD2IdentificationEntry; |
||
364 | ude.GetIdNames(outSL); |
||
365 | end; |
||
366 | end; |
||
367 | end; |
||
68 | daniel-mar | 368 | |
81 | daniel-mar | 369 | function TUD2.FulfilsEverySubterm(idTerm: WideString; slIdNames: TStrings=nil): boolean; |
82 | daniel-mar | 370 | const |
371 | CASE_SENSITIVE_FLAG = '$CASESENSITIVE$'; |
||
81 | daniel-mar | 372 | var |
373 | x: TArrayOfString; |
||
374 | i: integer; |
||
375 | idName: WideString; |
||
376 | cleanUpStringList: boolean; |
||
82 | daniel-mar | 377 | caseSensitive: boolean; |
81 | daniel-mar | 378 | begin |
379 | cleanUpStringList := slIdNames = nil; |
||
68 | daniel-mar | 380 | try |
81 | daniel-mar | 381 | if cleanUpStringList then |
68 | daniel-mar | 382 | begin |
81 | daniel-mar | 383 | slIdNames := TStringList.Create; |
384 | GetAllIdNames(slIdNames); |
||
385 | end; |
||
386 | |||
387 | SetLength(x, 0); |
||
388 | if Pos(':', idTerm) = 0 then |
||
389 | begin |
||
390 | result := false; |
||
391 | Exit; |
||
392 | end; |
||
393 | x := SplitString('&&', idTerm); |
||
394 | result := true; |
||
395 | for i := Low(x) to High(x) do |
||
396 | begin |
||
397 | idName := x[i]; |
||
398 | |||
82 | daniel-mar | 399 | if Pos(CASE_SENSITIVE_FLAG, idName) >= 1 then |
68 | daniel-mar | 400 | begin |
82 | daniel-mar | 401 | idName := StringReplace(idName, CASE_SENSITIVE_FLAG, '', [rfReplaceAll]); |
402 | caseSensitive := true; |
||
403 | end |
||
404 | else |
||
405 | begin |
||
406 | caseSensitive := false; |
||
407 | end; |
||
408 | |||
409 | if (not caseSensitive and (slIdNames.IndexOf(idName) = -1)) or |
||
410 | (caseSensitive and (IndexOf_CS(slIdNames, idName) = -1)) then |
||
411 | begin |
||
81 | daniel-mar | 412 | result := false; |
413 | break; |
||
68 | daniel-mar | 414 | end; |
415 | end; |
||
81 | daniel-mar | 416 | finally |
417 | if cleanUpStringList and Assigned(slIdNames) then |
||
418 | slIdNames.Free; |
||
419 | end; |
||
420 | end; |
||
68 | daniel-mar | 421 | |
81 | daniel-mar | 422 | procedure TUD2.GetCommandList(ShortTaskName: string; outSL: TStrings); |
423 | var |
||
424 | i: integer; |
||
425 | cmd: string; |
||
426 | idTerm: WideString; |
||
427 | slSV, slIdNames: TStrings; |
||
428 | nameVal: TArrayOfString; |
||
429 | begin |
||
430 | SetLength(nameVal, 0); |
||
431 | |||
432 | slIdNames := TStringList.Create; |
||
433 | try |
||
434 | GetAllIdNames(slIdNames); |
||
435 | |||
68 | daniel-mar | 436 | slSV := TStringList.Create; |
437 | try |
||
438 | FIniFile.ReadSectionValues(ShortTaskName, slSV); |
||
81 | daniel-mar | 439 | for i := 0 to slSV.Count-1 do |
68 | daniel-mar | 440 | begin |
441 | // We are doing the interpretation of the line ourselves, because |
||
442 | // TStringList.Values[] would not allow multiple command lines with the |
||
443 | // same key (idTerm) |
||
81 | daniel-mar | 444 | nameVal := SplitString('=', slSV.Strings[i]); |
68 | daniel-mar | 445 | idTerm := nameVal[0]; |
446 | cmd := nameVal[1]; |
||
447 | |||
81 | daniel-mar | 448 | if FulfilsEverySubterm(idTerm, slIdNames) then outSL.Add(cmd); |
68 | daniel-mar | 449 | end; |
450 | finally |
||
451 | slSV.Free; |
||
452 | end; |
||
453 | finally |
||
454 | slIdNames.Free; |
||
455 | end; |
||
456 | end; |
||
457 | |||
69 | daniel-mar | 458 | { TUD2PluginLoader } |
459 | |||
460 | procedure TUD2PluginLoader.Execute; |
||
461 | begin |
||
462 | inherited; |
||
463 | |||
464 | HandleDLL; |
||
465 | end; |
||
466 | |||
467 | constructor TUD2PluginLoader.Create(Suspended: boolean; DLL: string; alngid: LANGID); |
||
468 | begin |
||
469 | inherited Create(Suspended); |
||
470 | dllfile := dll; |
||
471 | pl := nil; |
||
472 | Errors := TStringList.Create; |
||
473 | lngid := alngid; |
||
474 | end; |
||
475 | |||
476 | destructor TUD2PluginLoader.Destroy; |
||
477 | begin |
||
478 | Errors.Free; |
||
479 | inherited; |
||
480 | end; |
||
481 | |||
70 | daniel-mar | 482 | function TUD2PluginLoader.HandleDLL: boolean; |
69 | daniel-mar | 483 | var |
484 | sIdentifier: WideString; |
||
485 | sIdentifiers: TArrayOfString; |
||
486 | buf: array[0..cchBufferSize-1] of WideChar; |
||
487 | pluginInterfaceID: TGUID; |
||
70 | daniel-mar | 488 | dllHandle: Cardinal; |
69 | daniel-mar | 489 | fPluginInterfaceID: TFuncPluginInterfaceID; |
490 | fPluginIdentifier: TFuncPluginIdentifier; |
||
491 | fPluginNameW: TFuncPluginNameW; |
||
492 | fPluginVendorW: TFuncPluginVendorW; |
||
493 | fPluginVersionW: TFuncPluginVersionW; |
||
494 | fIdentificationMethodNameW: TFuncIdentificationMethodNameW; |
||
495 | fIdentificationStringW: TFuncIdentificationStringW; |
||
496 | fCheckLicense: TFuncCheckLicense; |
||
70 | daniel-mar | 497 | fDescribeOwnStatusCodeW: TFuncDescribeOwnStatusCodeW; |
69 | daniel-mar | 498 | statusCode: UD2_STATUS; |
499 | i: integer; |
||
500 | starttime, endtime, time: cardinal; |
||
82 | daniel-mar | 501 | bakErrorMode: DWORD; |
502 | err: DWORD; |
||
70 | daniel-mar | 503 | |
504 | function _ErrorLookup(statusCode: UD2_STATUS): WideString; |
||
505 | var |
||
506 | ret: BOOL; |
||
507 | begin |
||
82 | daniel-mar | 508 | if Assigned(fDescribeOwnStatusCodeW) then |
70 | daniel-mar | 509 | begin |
82 | daniel-mar | 510 | ZeroMemory(@buf, cchBufferSize); |
511 | ret := fDescribeOwnStatusCodeW(@buf, cchBufferSize, statusCode, lngID); |
||
512 | if ret then |
||
513 | begin |
||
514 | result := PWideChar(@buf); |
||
515 | Exit; |
||
516 | end; |
||
70 | daniel-mar | 517 | end; |
518 | result := TUD2.GenericErrorLookup(statusCode); |
||
519 | end; |
||
520 | |||
82 | daniel-mar | 521 | function _ApplyCompatibilityGUID: boolean; |
522 | var |
||
523 | iniConfig: TIniFile; |
||
524 | sOverrideGUID: string; |
||
525 | sPluginConfigFile: string; |
||
69 | daniel-mar | 526 | begin |
82 | daniel-mar | 527 | result := false; |
69 | daniel-mar | 528 | sPluginConfigFile := ChangeFileExt(dllFile, '.ini'); |
529 | if FileExists(sPluginConfigFile) then |
||
530 | begin |
||
531 | iniConfig := TIniFile.Create(sPluginConfigFile); |
||
532 | try |
||
533 | sOverrideGUID := iniConfig.ReadString('Compatibility', 'OverrideGUID', ''); |
||
534 | if sOverrideGUID <> '' then |
||
535 | begin |
||
536 | pl.PluginGUID := StringToGUID(sOverrideGUID); |
||
82 | daniel-mar | 537 | result := true; |
69 | daniel-mar | 538 | end; |
539 | finally |
||
540 | iniConfig.Free; |
||
541 | end; |
||
542 | end; |
||
82 | daniel-mar | 543 | end; |
69 | daniel-mar | 544 | |
82 | daniel-mar | 545 | function _AutoOSNotSupportedMode: integer; |
546 | var |
||
547 | iniConfig: TIniFile; |
||
548 | sPluginConfigFile: string; |
||
549 | begin |
||
550 | result := 0; |
||
551 | sPluginConfigFile := ChangeFileExt(dllFile, '.ini'); |
||
552 | if FileExists(sPluginConfigFile) then |
||
69 | daniel-mar | 553 | begin |
82 | daniel-mar | 554 | iniConfig := TIniFile.Create(sPluginConfigFile); |
555 | try |
||
556 | result := iniConfig.ReadInteger('Compatibility', 'AutoOSNotSupported', 0); |
||
557 | finally |
||
558 | iniConfig.Free; |
||
69 | daniel-mar | 559 | end; |
560 | end; |
||
82 | daniel-mar | 561 | end; |
69 | daniel-mar | 562 | |
82 | daniel-mar | 563 | procedure _OverwriteStatusToOSNotSupported; |
564 | begin |
||
565 | pl := TUD2Plugin.Create; |
||
566 | pl.PluginDLL := dllFile; |
||
567 | statusCode := UD2_STATUS_NOTAVAIL_OS_NOT_SUPPORTED; |
||
568 | pl.IdentificationProcedureStatusCode := statusCode; |
||
569 | pl.IdentificationProcedureStatusCodeDescribed := _ErrorLookup(statusCode); |
||
570 | (* |
||
571 | if not _ApplyCompatibilityGUID then |
||
69 | daniel-mar | 572 | begin |
82 | daniel-mar | 573 | CreateGUID(pl.PluginGUID); // to avoid the "double GUID" error |
69 | daniel-mar | 574 | end; |
82 | daniel-mar | 575 | *) |
576 | pl.OSNotSupportedEnforced := true; // to avoid the "double GUID" error |
||
577 | result := true; |
||
578 | end; |
||
69 | daniel-mar | 579 | |
82 | daniel-mar | 580 | resourcestring |
581 | LNG_DLL_NOT_LOADED = 'Plugin DLL "%s" could not be loaded: %s'; |
||
582 | LNG_METHOD_NOT_FOUND = 'Method "%s" not found in plugin "%s". The DLL is probably not a valid plugin DLL.'; |
||
583 | LNG_INVALID_PLUGIN = 'The plugin "%s" is not a valid plugin for this application.'; |
||
584 | LNG_METHOD_FAILURE = 'Error "%s" at method "%s" of plugin "%s".'; |
||
585 | LNG_EXCEPTION = 'Fatal error while loading "%s" (%s: %s)'; |
||
586 | begin |
||
587 | result := false; |
||
588 | startTime := GetTickCount; |
||
69 | daniel-mar | 589 | |
82 | daniel-mar | 590 | try |
591 | bakErrorMode := 0; |
||
592 | UD2_SetThreadErrorMode(SEM_FAILCRITICALERRORS, Pointer(bakErrorMode)); |
||
593 | try |
||
594 | dllHandle := LoadLibrary(PChar(dllFile)); |
||
595 | if dllHandle = 0 then |
||
596 | begin |
||
597 | err := GetLastError; |
||
69 | daniel-mar | 598 | |
82 | daniel-mar | 599 | if ((_AutoOSNotSupportedMode = 1) and ((err = ERROR_DLL_NOT_FOUND) or (err = ERROR_PROC_NOT_FOUND))) or |
600 | (_AutoOSNotSupportedMode >= 2) then |
||
601 | begin |
||
602 | _OverwriteStatusToOSNotSupported; |
||
603 | Exit; |
||
604 | end; |
||
69 | daniel-mar | 605 | |
82 | daniel-mar | 606 | Errors.Add(Format(LNG_DLL_NOT_LOADED, [dllFile, SysErrorMessage(err)])); |
607 | Exit; |
||
608 | end; |
||
609 | try |
||
610 | @fPluginInterfaceID := GetProcAddress(dllHandle, mnPluginInterfaceID); |
||
611 | if not Assigned(fPluginInterfaceID) then |
||
612 | begin |
||
613 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginInterfaceID, dllFile])); |
||
614 | Exit; |
||
615 | end; |
||
616 | pluginInterfaceID := fPluginInterfaceID(); |
||
617 | if not IsEqualGUID(pluginInterfaceID, GUID_USERDETECT2_IDPLUGIN_V1) then |
||
618 | begin |
||
619 | Errors.Add(Format(LNG_INVALID_PLUGIN, [dllFile])); |
||
620 | Exit; |
||
621 | end; |
||
69 | daniel-mar | 622 | |
82 | daniel-mar | 623 | @fIdentificationStringW := GetProcAddress(dllHandle, mnIdentificationStringW); |
624 | if not Assigned(fIdentificationStringW) then |
||
69 | daniel-mar | 625 | begin |
82 | daniel-mar | 626 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnIdentificationStringW, dllFile])); |
627 | Exit; |
||
69 | daniel-mar | 628 | end; |
82 | daniel-mar | 629 | |
630 | @fPluginNameW := GetProcAddress(dllHandle, mnPluginNameW); |
||
631 | if not Assigned(fPluginNameW) then |
||
632 | begin |
||
633 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginNameW, dllFile])); |
||
634 | Exit; |
||
635 | end; |
||
636 | |||
637 | @fPluginVendorW := GetProcAddress(dllHandle, mnPluginVendorW); |
||
638 | if not Assigned(fPluginVendorW) then |
||
639 | begin |
||
640 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginVendorW, dllFile])); |
||
641 | Exit; |
||
642 | end; |
||
643 | |||
644 | @fPluginVersionW := GetProcAddress(dllHandle, mnPluginVersionW); |
||
645 | if not Assigned(fPluginVersionW) then |
||
646 | begin |
||
647 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginVersionW, dllFile])); |
||
648 | Exit; |
||
649 | end; |
||
650 | |||
651 | @fCheckLicense := GetProcAddress(dllHandle, mnCheckLicense); |
||
652 | if not Assigned(fCheckLicense) then |
||
653 | begin |
||
654 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnCheckLicense, dllFile])); |
||
655 | Exit; |
||
656 | end; |
||
657 | |||
658 | @fIdentificationMethodNameW := GetProcAddress(dllHandle, mnIdentificationMethodNameW); |
||
659 | if not Assigned(fIdentificationMethodNameW) then |
||
660 | begin |
||
661 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnIdentificationMethodNameW, dllFile])); |
||
662 | Exit; |
||
663 | end; |
||
664 | |||
665 | @fDescribeOwnStatusCodeW := GetProcAddress(dllHandle, mnDescribeOwnStatusCodeW); |
||
666 | if not Assigned(fDescribeOwnStatusCodeW) then |
||
667 | begin |
||
668 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnDescribeOwnStatusCodeW, dllFile])); |
||
669 | Exit; |
||
670 | end; |
||
671 | |||
672 | pl := TUD2Plugin.Create; |
||
673 | pl.PluginDLL := dllFile; |
||
674 | |||
675 | if not _ApplyCompatibilityGUID then |
||
676 | begin |
||
677 | @fPluginIdentifier := GetProcAddress(dllHandle, mnPluginIdentifier); |
||
678 | if not Assigned(fPluginIdentifier) then |
||
679 | begin |
||
680 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginIdentifier, dllFile])); |
||
681 | Exit; |
||
682 | end; |
||
683 | pl.PluginGUID := fPluginIdentifier(); |
||
684 | end; |
||
685 | |||
686 | statusCode := fCheckLicense(nil); |
||
687 | if statusCode.wCategory = UD2_STATUSCAT_FAILED then |
||
688 | begin |
||
689 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnCheckLicense, dllFile])); |
||
690 | Exit; |
||
691 | end; |
||
692 | |||
693 | ZeroMemory(@buf, cchBufferSize); |
||
694 | statusCode := fPluginNameW(@buf, cchBufferSize, lngID); |
||
695 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then pl.PluginName := PWideChar(@buf) |
||
696 | else if statusCode.wCategory = UD2_STATUSCAT_NOT_AVAIL then pl.PluginName := '' |
||
697 | else |
||
698 | begin |
||
699 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginNameW, dllFile])); |
||
700 | Exit; |
||
701 | end; |
||
702 | |||
703 | ZeroMemory(@buf, cchBufferSize); |
||
704 | statusCode := fPluginVendorW(@buf, cchBufferSize, lngID); |
||
705 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then pl.PluginVendor := PWideChar(@buf) |
||
706 | else if statusCode.wCategory = UD2_STATUSCAT_NOT_AVAIL then pl.PluginVendor := '' |
||
707 | else |
||
708 | begin |
||
709 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginVendorW, dllFile])); |
||
710 | Exit; |
||
711 | end; |
||
712 | |||
713 | ZeroMemory(@buf, cchBufferSize); |
||
714 | statusCode := fPluginVersionW(@buf, cchBufferSize, lngID); |
||
715 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then pl.PluginVersion := PWideChar(@buf) |
||
716 | else if statusCode.wCategory = UD2_STATUSCAT_NOT_AVAIL then pl.PluginVersion := '' |
||
717 | else |
||
718 | begin |
||
719 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginVersionW, dllFile])); |
||
720 | Exit; |
||
721 | end; |
||
722 | |||
723 | ZeroMemory(@buf, cchBufferSize); |
||
724 | statusCode := fIdentificationMethodNameW(@buf, cchBufferSize); |
||
725 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then pl.IdentificationMethodName := PWideChar(@buf) |
||
726 | else if statusCode.wCategory = UD2_STATUSCAT_NOT_AVAIL then pl.IdentificationMethodName := '' |
||
727 | else |
||
728 | begin |
||
729 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnIdentificationMethodNameW, dllFile])); |
||
730 | Exit; |
||
731 | end; |
||
732 | |||
733 | ZeroMemory(@buf, cchBufferSize); |
||
734 | statusCode := UD2_STATUS_FAILURE_NO_RETURNED_VALUE; // This status will be used when the DLL does not return anything (which is an error by the developer) |
||
735 | statusCode := fIdentificationStringW(@buf, cchBufferSize); |
||
736 | pl.IdentificationProcedureStatusCode := statusCode; |
||
737 | pl.IdentificationProcedureStatusCodeDescribed := _ErrorLookup(statusCode); |
||
738 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then |
||
739 | begin |
||
740 | sIdentifier := PWideChar(@buf); |
||
741 | if UD2_STATUS_Equal(statusCode, UD2_STATUS_OK_MULTILINE, false) then |
||
742 | begin |
||
743 | // Multiple identifiers (e.g. multiple MAC addresses are delimited via UD2_MULTIPLE_ITEMS_DELIMITER) |
||
744 | SetLength(sIdentifiers, 0); |
||
745 | sIdentifiers := SplitString(UD2_MULTIPLE_ITEMS_DELIMITER, sIdentifier); |
||
746 | for i := Low(sIdentifiers) to High(sIdentifiers) do |
||
747 | begin |
||
748 | pl.AddIdentification(sIdentifiers[i]); |
||
749 | end; |
||
750 | end |
||
751 | else |
||
752 | begin |
||
753 | pl.AddIdentification(sIdentifier); |
||
754 | end; |
||
755 | end |
||
756 | else if statusCode.wCategory <> UD2_STATUSCAT_NOT_AVAIL then |
||
757 | begin |
||
758 | if _AutoOSNotSupportedMode >= 3 then |
||
759 | begin |
||
760 | _OverwriteStatusToOSNotSupported; |
||
761 | Exit; |
||
762 | end; |
||
763 | |||
764 | // Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnIdentificationStringW, dllFile])); |
||
765 | Errors.Add(Format(LNG_METHOD_FAILURE, [pl.IdentificationProcedureStatusCodeDescribed, mnIdentificationStringW, dllFile])); |
||
766 | Exit; |
||
767 | end; |
||
768 | |||
769 | result := true; |
||
770 | finally |
||
771 | if not result and Assigned(pl) then FreeAndNil(pl); |
||
772 | FreeLibrary(dllHandle); |
||
773 | end; |
||
774 | finally |
||
775 | UD2_SetThreadErrorMode(bakErrorMode, nil); |
||
776 | |||
777 | if result then |
||
69 | daniel-mar | 778 | begin |
82 | daniel-mar | 779 | endtime := GetTickCount; |
780 | time := endtime - starttime; |
||
781 | if endtime < starttime then time := High(Cardinal) - time; |
||
782 | pl.time := time; |
||
69 | daniel-mar | 783 | end; |
82 | daniel-mar | 784 | end; |
785 | except |
||
786 | // TODO: when an exception happens in a cdecl DLL, then this code is somehow not |
||
787 | // executed. Probably the memory is corrupted. Anyway, a cdecl DLL shall NEVER |
||
788 | // raise an Exception. |
||
789 | on E: Exception do |
||
69 | daniel-mar | 790 | begin |
82 | daniel-mar | 791 | Errors.Add(Format(LNG_EXCEPTION, [dllFile, E.ClassName, E.Message])); |
69 | daniel-mar | 792 | Exit; |
793 | end; |
||
794 | end; |
||
795 | end; |
||
796 | |||
68 | daniel-mar | 797 | end. |