Rev 84 | Rev 86 | 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, |
85 | daniel-mar | 13 | UD2_PluginStatus, UD2_Utils, UD2_Parsing; |
68 | daniel-mar | 14 | |
15 | type |
||
83 | daniel-mar | 16 | TUD2IdentificationEntry = class; |
17 | |||
68 | daniel-mar | 18 | TUD2Plugin = class(TObject) |
19 | protected |
||
20 | FDetectedIdentifications: TObjectList{<TUD2IdentificationEntry>}; |
||
21 | public |
||
82 | daniel-mar | 22 | // This flag will be set if "AutoOSNotSupportedCompatibility" of the INI manifest had to be enforced/used |
23 | OSNotSupportedEnforced: boolean; |
||
24 | |||
68 | daniel-mar | 25 | PluginDLL: string; |
26 | PluginGUID: TGUID; |
||
27 | PluginName: WideString; |
||
28 | PluginVendor: WideString; |
||
29 | PluginVersion: WideString; |
||
30 | IdentificationMethodName: WideString; |
||
70 | daniel-mar | 31 | |
32 | // ONLY contains the non-failure status code of IdentificationStringW |
||
33 | IdentificationProcedureStatusCode: UD2_STATUS; |
||
34 | IdentificationProcedureStatusCodeDescribed: WideString; |
||
83 | daniel-mar | 35 | |
69 | daniel-mar | 36 | Time: Cardinal; |
68 | daniel-mar | 37 | function PluginGUIDString: string; |
83 | daniel-mar | 38 | property DetectedIdentifications: TObjectList{<TUD2IdentificationEntry>} read FDetectedIdentifications; |
68 | daniel-mar | 39 | destructor Destroy; override; |
40 | constructor Create; |
||
83 | daniel-mar | 41 | function AddIdentification(IdStr: WideString): TUD2IdentificationEntry; |
42 | |||
43 | function InvokeDynamicCheck(dynamicData: string): boolean; |
||
44 | function GetDynamicRequestResult(dynamicData: string): TArrayOfString; |
||
45 | |||
46 | function EqualsMethodNameOrGuid(idMethodNameOrGUID: string): boolean; |
||
68 | daniel-mar | 47 | end; |
48 | |||
49 | TUD2IdentificationEntry = class(TObject) |
||
50 | private |
||
51 | FIdentificationString: WideString; |
||
52 | FPlugin: TUD2Plugin; |
||
83 | daniel-mar | 53 | FDynamicDataUsed: boolean; |
54 | FDynamicData: string; |
||
68 | daniel-mar | 55 | public |
83 | daniel-mar | 56 | property DynamicDataUsed: boolean read FDynamicDataUsed write FDynamicDataUsed; |
57 | property DynamicData: string read FDynamicData write FDynamicData; |
||
68 | daniel-mar | 58 | property IdentificationString: WideString read FIdentificationString; |
59 | property Plugin: TUD2Plugin read FPlugin; |
||
60 | procedure GetIdNames(sl: TStrings); |
||
61 | constructor Create(AIdentificationString: WideString; APlugin: TUD2Plugin); |
||
62 | end; |
||
63 | |||
64 | TUD2 = class(TObject) |
||
65 | private |
||
70 | daniel-mar | 66 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
68 | daniel-mar | 67 | FGUIDLookup: TStrings; |
70 | daniel-mar | 68 | {$ENDIF} |
68 | daniel-mar | 69 | protected |
70 | FLoadedPlugins: TObjectList{<TUD2Plugin>}; |
||
71 | FIniFile: TMemIniFile; |
||
72 | FErrors: TStrings; |
||
73 | FIniFileName: string; |
||
74 | public |
||
75 | property IniFileName: string read FIniFileName; |
||
76 | property Errors: TStrings read FErrors; |
||
77 | property LoadedPlugins: TObjectList{<TUD2Plugin>} read FLoadedPlugins; |
||
78 | property IniFile: TMemIniFile read FIniFile; |
||
84 | daniel-mar | 79 | procedure GetAllDetectedIDs(outSL: TStrings); |
85 | daniel-mar | 80 | function FulfilsEverySubterm(conds: TUD2TDFConditionArray; slIdNames: TStrings=nil): boolean; overload; |
81 | function FulfilsEverySubterm(idTerm: WideString; slIdNames: TStrings=nil): boolean; overload; |
||
82 | function CheckTerm(idTermAndCmd: string; slIdNames: TStrings=nil): TUD2CommandArray; |
||
83 | daniel-mar | 83 | function FindPluginByMethodNameOrGuid(idMethodName: string): TUD2Plugin; |
85 | daniel-mar | 84 | function GetCommandList(ShortTaskName: string): TUD2CommandArray; |
80 | daniel-mar | 85 | procedure HandlePluginDir(APluginDir, AFileMask: string); |
68 | daniel-mar | 86 | procedure GetTaskListing(outSL: TStrings); |
87 | constructor Create(AIniFileName: string); |
||
88 | destructor Destroy; override; |
||
89 | function TaskExists(ShortTaskName: string): boolean; |
||
80 | daniel-mar | 90 | function ReadMetatagString(ShortTaskName, MetatagName: string; DefaultVal: string): string; |
91 | function ReadMetatagBool(ShortTaskName, MetatagName: string; DefaultVal: string): boolean; |
||
68 | daniel-mar | 92 | function GetTaskName(AShortTaskName: string): string; |
71 | daniel-mar | 93 | class function GenericErrorLookup(grStatus: UD2_STATUS): string; |
68 | daniel-mar | 94 | end; |
95 | |||
96 | implementation |
||
97 | |||
98 | uses |
||
83 | daniel-mar | 99 | Math; |
68 | daniel-mar | 100 | |
84 | daniel-mar | 101 | const |
102 | cchBufferSize = 32768; |
||
103 | |||
69 | daniel-mar | 104 | type |
105 | TUD2PluginLoader = class(TThread) |
||
106 | protected |
||
107 | dllFile: string; |
||
108 | lngID: LANGID; |
||
83 | daniel-mar | 109 | useDynamicData: boolean; |
110 | dynamicData: WideString; |
||
69 | daniel-mar | 111 | procedure Execute; override; |
70 | daniel-mar | 112 | function HandleDLL: boolean; |
69 | daniel-mar | 113 | public |
83 | daniel-mar | 114 | pl: TUD2Plugin; // TODO: why do we need it?! can it be leaked if we use it for dynamic requests? |
69 | daniel-mar | 115 | Errors: TStringList; |
83 | daniel-mar | 116 | ResultIdentifiers: TArrayOfString; |
117 | constructor Create(Suspended: boolean; DLL: string; alngid: LANGID; useDynamicData: boolean; dynamicData: WideString); |
||
69 | daniel-mar | 118 | destructor Destroy; override; |
119 | end; |
||
120 | |||
71 | daniel-mar | 121 | class function TUD2.GenericErrorLookup(grStatus: UD2_STATUS): string; |
68 | daniel-mar | 122 | resourcestring |
80 | daniel-mar | 123 | LNG_STATUS_OK_UNSPECIFIED = 'Success (Unspecified)'; |
124 | LNG_STATUS_OK_SINGLELINE = 'Success (One identifier returned)'; |
||
125 | LNG_STATUS_OK_MULTILINE = 'Success (Multiple identifiers returned)'; |
||
126 | LNG_UNKNOWN_SUCCESS = 'Success (Unknown status code %s)'; |
||
69 | daniel-mar | 127 | |
80 | daniel-mar | 128 | LNG_STATUS_NOTAVAIL_UNSPECIFIED = 'Not available (Unspecified)'; |
129 | LNG_STATUS_NOTAVAIL_OS_NOT_SUPPORTED = 'Not available (Operating system not supported)'; |
||
130 | LNG_STATUS_NOTAVAIL_HW_NOT_SUPPORTED = 'Not available (Hardware not supported)'; |
||
131 | LNG_STATUS_NOTAVAIL_NO_ENTITIES = 'Not available (No entities to identify)'; |
||
132 | LNG_STATUS_NOTAVAIL_WINAPI_CALL_FAILURE = 'Not available (A Windows API call failed. Message: %s)'; |
||
83 | daniel-mar | 133 | LNG_STATUS_NOTAVAIL_ONLY_ACCEPT_DYNAMIC = 'Not available (Arguments required)'; |
80 | daniel-mar | 134 | LNG_UNKNOWN_NOTAVAIL = 'Not available (Unknown status code %s)'; |
69 | daniel-mar | 135 | |
82 | daniel-mar | 136 | LNG_STATUS_FAILURE_UNSPECIFIED = 'Error (Unspecified)'; |
137 | LNG_STATUS_FAILURE_BUFFER_TOO_SMALL = 'Error (The provided buffer is too small!)'; |
||
138 | LNG_STATUS_FAILURE_INVALID_ARGS = 'Error (The function received invalid arguments!)'; |
||
139 | LNG_STATUS_FAILURE_PLUGIN_NOT_LICENSED = 'Error (The plugin is not licensed)'; |
||
140 | LNG_STATUS_FAILURE_NO_RETURNED_VALUE = 'Error (Plugin did not return a status)'; |
||
141 | LNG_STATUS_FAILURE_CATCHED_EXCEPTION = 'Error (Catched unexpected Exception)'; |
||
80 | daniel-mar | 142 | LNG_UNKNOWN_FAILED = 'Error (Unknown status code %s)'; |
69 | daniel-mar | 143 | |
71 | daniel-mar | 144 | LNG_UNKNOWN_STATUS = 'Unknown status code with unexpected category: %s'; |
68 | daniel-mar | 145 | begin |
71 | daniel-mar | 146 | if UD2_STATUS_Equal(grStatus, UD2_STATUS_OK_UNSPECIFIED, false) then result := LNG_STATUS_OK_UNSPECIFIED |
147 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_OK_SINGLELINE, false) then result := LNG_STATUS_OK_SINGLELINE |
||
148 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_OK_MULTILINE, false) then result := LNG_STATUS_OK_MULTILINE |
||
69 | daniel-mar | 149 | |
71 | daniel-mar | 150 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_UNSPECIFIED, false) then result := LNG_STATUS_NOTAVAIL_UNSPECIFIED |
151 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_OS_NOT_SUPPORTED, false) then result := LNG_STATUS_NOTAVAIL_OS_NOT_SUPPORTED |
||
152 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_HW_NOT_SUPPORTED, false) then result := LNG_STATUS_NOTAVAIL_HW_NOT_SUPPORTED |
||
153 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_NO_ENTITIES, false) then result := LNG_STATUS_NOTAVAIL_NO_ENTITIES |
||
154 | 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)]) |
||
83 | daniel-mar | 155 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_NOTAVAIL_ONLY_ACCEPT_DYNAMIC, false) then result := LNG_STATUS_NOTAVAIL_ONLY_ACCEPT_DYNAMIC |
69 | daniel-mar | 156 | |
82 | daniel-mar | 157 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_UNSPECIFIED, false) then result := LNG_STATUS_FAILURE_UNSPECIFIED |
158 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_BUFFER_TOO_SMALL, false) then result := LNG_STATUS_FAILURE_BUFFER_TOO_SMALL |
||
159 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_INVALID_ARGS, false) then result := LNG_STATUS_FAILURE_INVALID_ARGS |
||
160 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_PLUGIN_NOT_LICENSED, false) then result := LNG_STATUS_FAILURE_PLUGIN_NOT_LICENSED |
||
161 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_NO_RETURNED_VALUE, false) then result := LNG_STATUS_FAILURE_NO_RETURNED_VALUE |
||
162 | else if UD2_STATUS_Equal(grStatus, UD2_STATUS_FAILURE_CATCHED_EXCEPTION, false) then result := LNG_STATUS_FAILURE_CATCHED_EXCEPTION |
||
69 | daniel-mar | 163 | |
71 | daniel-mar | 164 | else if grStatus.wCategory = UD2_STATUSCAT_SUCCESS then result := Format(LNG_UNKNOWN_SUCCESS, [UD2_STATUS_FormatStatusCode(grStatus)]) |
165 | else if grStatus.wCategory = UD2_STATUSCAT_NOT_AVAIL then result := Format(LNG_UNKNOWN_NOTAVAIL, [UD2_STATUS_FormatStatusCode(grStatus)]) |
||
166 | else if grStatus.wCategory = UD2_STATUSCAT_FAILED then result := Format(LNG_UNKNOWN_FAILED, [UD2_STATUS_FormatStatusCode(grStatus)]) |
||
167 | else result := Format(LNG_UNKNOWN_STATUS, [UD2_STATUS_FormatStatusCode(grStatus)]); |
||
68 | daniel-mar | 168 | end; |
169 | |||
170 | { TUD2Plugin } |
||
171 | |||
172 | function TUD2Plugin.PluginGUIDString: string; |
||
173 | begin |
||
174 | result := UpperCase(GUIDToString(PluginGUID)); |
||
175 | end; |
||
176 | |||
83 | daniel-mar | 177 | function TUD2Plugin.AddIdentification(IdStr: WideString): TUD2IdentificationEntry; |
68 | daniel-mar | 178 | begin |
83 | daniel-mar | 179 | result := TUD2IdentificationEntry.Create(IdStr, Self); |
180 | DetectedIdentifications.Add(result); |
||
68 | daniel-mar | 181 | end; |
182 | |||
183 | destructor TUD2Plugin.Destroy; |
||
184 | begin |
||
185 | DetectedIdentifications.Free; |
||
186 | inherited; |
||
187 | end; |
||
188 | |||
189 | constructor TUD2Plugin.Create; |
||
190 | begin |
||
191 | inherited Create; |
||
192 | FDetectedIdentifications := TObjectList{<TUD2IdentificationEntry>}.Create(true); |
||
193 | end; |
||
194 | |||
83 | daniel-mar | 195 | function TUD2Plugin.InvokeDynamicCheck(dynamicData: string): boolean; |
196 | var |
||
197 | ude: TUD2IdentificationEntry; |
||
198 | i: integer; |
||
199 | ids: TArrayOfString; |
||
200 | id: string; |
||
201 | begin |
||
202 | result := false; |
||
68 | daniel-mar | 203 | |
83 | daniel-mar | 204 | for i := 0 to FDetectedIdentifications.Count-1 do |
205 | begin |
||
206 | ude := FDetectedIdentifications.Items[i] as TUD2IdentificationEntry; |
||
207 | if ude.dynamicDataUsed and (ude.dynamicData = dynamicData) then |
||
208 | begin |
||
209 | // The dynamic content was already evaluated (and therefore is already added in FDetectedIdentifications). |
||
210 | Exit; |
||
211 | end; |
||
212 | end; |
||
213 | |||
214 | SetLength(ids, 0); |
||
215 | ids := GetDynamicRequestResult(dynamicData); |
||
216 | |||
217 | for i := 0 to Length(ids)-1 do |
||
218 | begin |
||
219 | id := ids[i]; |
||
220 | |||
221 | ude := AddIdentification(id); |
||
222 | ude.dynamicDataUsed := true; |
||
223 | ude.dynamicData := dynamicData; |
||
224 | |||
225 | result := true; |
||
226 | end; |
||
227 | end; |
||
228 | |||
229 | function TUD2Plugin.GetDynamicRequestResult(dynamicData: string): TArrayOfString; |
||
230 | var |
||
231 | lngID: LANGID; |
||
232 | pll: TUD2PluginLoader; |
||
68 | daniel-mar | 233 | begin |
83 | daniel-mar | 234 | lngID := GetSystemDefaultLangID; |
235 | |||
236 | pll := TUD2PluginLoader.Create(false, PluginDLL, lngid, true, dynamicData); |
||
237 | try |
||
238 | pll.WaitFor; |
||
239 | result := pll.ResultIdentifiers; |
||
240 | finally |
||
241 | pll.Free; |
||
242 | end; |
||
68 | daniel-mar | 243 | end; |
244 | |||
83 | daniel-mar | 245 | function TUD2Plugin.EqualsMethodNameOrGuid(idMethodNameOrGUID: string): boolean; |
246 | begin |
||
247 | result := SameText(IdentificationMethodName, idMethodNameOrGUID) or |
||
248 | SameText(GUIDToString(PluginGUID), idMethodNameOrGUID) |
||
249 | end; |
||
250 | |||
251 | { TUD2IdentificationEntry } |
||
252 | |||
68 | daniel-mar | 253 | procedure TUD2IdentificationEntry.GetIdNames(sl: TStrings); |
85 | daniel-mar | 254 | var |
255 | cond: TUD2TDFCondition; |
||
68 | daniel-mar | 256 | begin |
85 | daniel-mar | 257 | cond.idMethodName := Plugin.IdentificationMethodName; |
258 | cond.idStr := IdentificationString; |
||
259 | cond.dynamicDataUsed := DynamicDataUsed; |
||
260 | cond.dynamicData := DynamicData; |
||
261 | sl.Add(UD2_CondToStr(cond)); |
||
262 | |||
263 | cond.idMethodName := Plugin.PluginGUIDString; |
||
264 | sl.Add(UD2_CondToStr(cond)); |
||
68 | daniel-mar | 265 | end; |
266 | |||
267 | constructor TUD2IdentificationEntry.Create(AIdentificationString: WideString; |
||
268 | APlugin: TUD2Plugin); |
||
269 | begin |
||
270 | inherited Create; |
||
271 | FIdentificationString := AIdentificationString; |
||
272 | FPlugin := APlugin; |
||
273 | end; |
||
274 | |||
275 | { TUD2 } |
||
276 | |||
80 | daniel-mar | 277 | procedure TUD2.HandlePluginDir(APluginDir, AFileMask: string); |
69 | daniel-mar | 278 | Var |
279 | SR: TSearchRec; |
||
280 | path: string; |
||
70 | daniel-mar | 281 | pluginLoader: TUD2PluginLoader; |
69 | daniel-mar | 282 | tob: TObjectList; |
68 | daniel-mar | 283 | i: integer; |
70 | daniel-mar | 284 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
285 | sPluginID, prevDLL: string; |
||
286 | {$ENDIF} |
||
69 | daniel-mar | 287 | lngid: LANGID; |
68 | daniel-mar | 288 | resourcestring |
289 | LNG_PLUGINS_SAME_GUID = 'Attention: The plugin "%s" and the plugin "%s" have the same identification GUID. The latter will not be loaded.'; |
||
290 | begin |
||
69 | daniel-mar | 291 | tob := TObjectList.Create; |
68 | daniel-mar | 292 | try |
69 | daniel-mar | 293 | tob.OwnsObjects := false; |
68 | daniel-mar | 294 | |
69 | daniel-mar | 295 | lngID := GetSystemDefaultLangID; |
68 | daniel-mar | 296 | |
80 | daniel-mar | 297 | path := APluginDir; |
298 | if path <> '' then path := IncludeTrailingPathDelimiter(path); |
||
299 | |||
300 | if FindFirst(path + AFileMask, 0, SR) = 0 then |
||
68 | daniel-mar | 301 | begin |
302 | try |
||
69 | daniel-mar | 303 | repeat |
304 | try |
||
83 | daniel-mar | 305 | tob.Add(TUD2PluginLoader.Create(false, path + sr.Name, lngid, false, '')); |
69 | daniel-mar | 306 | except |
307 | on E: Exception do |
||
308 | begin |
||
309 | MessageDlg(E.Message, mtError, [mbOK], 0); |
||
310 | end; |
||
311 | end; |
||
312 | until FindNext(SR) <> 0; |
||
68 | daniel-mar | 313 | finally |
69 | daniel-mar | 314 | FindClose(SR); |
68 | daniel-mar | 315 | end; |
316 | end; |
||
317 | |||
69 | daniel-mar | 318 | for i := 0 to tob.count-1 do |
68 | daniel-mar | 319 | begin |
70 | daniel-mar | 320 | pluginLoader := tob.items[i] as TUD2PluginLoader; |
321 | pluginLoader.WaitFor; |
||
322 | Errors.AddStrings(pluginLoader.Errors); |
||
323 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
||
324 | if Assigned(pluginLoader.pl) then |
||
68 | daniel-mar | 325 | begin |
82 | daniel-mar | 326 | if not pluginLoader.pl.OSNotSupportedEnforced then |
69 | daniel-mar | 327 | begin |
82 | daniel-mar | 328 | sPluginID := GUIDToString(pluginLoader.pl.PluginGUID); |
329 | prevDLL := FGUIDLookup.Values[sPluginID]; |
||
330 | if (prevDLL <> '') and (prevDLL <> pluginLoader.pl.PluginDLL) then |
||
331 | begin |
||
332 | Errors.Add(Format(LNG_PLUGINS_SAME_GUID, [prevDLL, pluginLoader.pl.PluginDLL])); |
||
333 | pluginLoader.pl.Free; |
||
334 | end |
||
335 | else |
||
336 | begin |
||
337 | FGUIDLookup.Values[sPluginID] := pluginLoader.pl.PluginDLL; |
||
338 | LoadedPlugins.Add(pluginLoader.pl); |
||
339 | end; |
||
69 | daniel-mar | 340 | end; |
68 | daniel-mar | 341 | end; |
70 | daniel-mar | 342 | {$ENDIF} |
343 | pluginLoader.Free; |
||
68 | daniel-mar | 344 | end; |
345 | finally |
||
69 | daniel-mar | 346 | tob.free; |
68 | daniel-mar | 347 | end; |
348 | end; |
||
349 | |||
350 | destructor TUD2.Destroy; |
||
351 | begin |
||
352 | FIniFile.Free; |
||
353 | FLoadedPlugins.Free; |
||
70 | daniel-mar | 354 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
68 | daniel-mar | 355 | FGUIDLookup.Free; |
70 | daniel-mar | 356 | {$ENDIF} |
68 | daniel-mar | 357 | FErrors.Free; |
358 | end; |
||
359 | |||
360 | constructor TUD2.Create(AIniFileName: string); |
||
361 | begin |
||
362 | FIniFileName := AIniFileName; |
||
363 | FLoadedPlugins := TObjectList{<TUD2Plugin>}.Create(true); |
||
364 | FIniFile := TMemIniFile.Create(IniFileName); |
||
70 | daniel-mar | 365 | {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID} |
68 | daniel-mar | 366 | FGUIDLookup := TStringList.Create; |
70 | daniel-mar | 367 | {$ENDIF} |
68 | daniel-mar | 368 | FErrors := TStringList.Create; |
369 | end; |
||
370 | |||
371 | function TUD2.GetTaskName(AShortTaskName: string): string; |
||
69 | daniel-mar | 372 | resourcestring |
373 | LNG_NO_DESCRIPTION = '(%s)'; |
||
68 | daniel-mar | 374 | begin |
69 | daniel-mar | 375 | result := FIniFile.ReadString(AShortTaskName, 'Description', Format(LNG_NO_DESCRIPTION, [AShortTaskName])); |
68 | daniel-mar | 376 | end; |
377 | |||
378 | procedure TUD2.GetTaskListing(outSL: TStrings); |
||
379 | var |
||
380 | sl: TStringList; |
||
381 | i: integer; |
||
382 | desc: string; |
||
383 | begin |
||
384 | sl := TStringList.Create; |
||
385 | try |
||
386 | FIniFile.ReadSections(sl); |
||
387 | for i := 0 to sl.Count-1 do |
||
388 | begin |
||
389 | desc := GetTaskName(sl.Strings[i]); |
||
390 | outSL.Values[sl.Strings[i]] := desc; |
||
391 | end; |
||
392 | finally |
||
393 | sl.Free; |
||
394 | end; |
||
395 | end; |
||
396 | |||
397 | function TUD2.TaskExists(ShortTaskName: string): boolean; |
||
398 | begin |
||
399 | result := FIniFile.SectionExists(ShortTaskName); |
||
400 | end; |
||
401 | |||
402 | function TUD2.ReadMetatagString(ShortTaskName, MetatagName: string; |
||
403 | DefaultVal: string): string; |
||
404 | begin |
||
405 | result := IniFile.ReadString(ShortTaskName, MetatagName, DefaultVal); |
||
406 | end; |
||
407 | |||
408 | function TUD2.ReadMetatagBool(ShortTaskName, MetatagName: string; |
||
409 | DefaultVal: string): boolean; |
||
410 | begin |
||
411 | // DefaultVal is a string, because we want to allow an empty string, in case the |
||
412 | // user wishes an Exception in case the string is not a valid boolean string |
||
413 | result := BetterInterpreteBool(IniFile.ReadString(ShortTaskName, MetatagName, DefaultVal)); |
||
414 | end; |
||
415 | |||
416 | (* |
||
417 | |||
84 | daniel-mar | 418 | NAMING EXAMPLE: $CASESENSITIVE$ComputerName(dynXYZ):ABC&&User:John=calc.exe$RIOD$ |
68 | daniel-mar | 419 | |
84 | daniel-mar | 420 | idTerm: ComputerName(dynXYZ):ABC&&User:John |
68 | daniel-mar | 421 | idName: ComputerName:ABC |
422 | IdMethodName: ComputerName |
||
423 | IdStr ABC |
||
424 | cmd: calc.exe |
||
83 | daniel-mar | 425 | dynamicData: dynXYZ |
68 | daniel-mar | 426 | |
427 | *) |
||
428 | |||
84 | daniel-mar | 429 | procedure TUD2.GetAllDetectedIDs(outSL: TStrings); |
68 | daniel-mar | 430 | var |
431 | i, j: integer; |
||
432 | pl: TUD2Plugin; |
||
433 | ude: TUD2IdentificationEntry; |
||
434 | begin |
||
81 | daniel-mar | 435 | for i := 0 to LoadedPlugins.Count-1 do |
436 | begin |
||
437 | pl := LoadedPlugins.Items[i] as TUD2Plugin; |
||
438 | for j := 0 to pl.DetectedIdentifications.Count-1 do |
||
439 | begin |
||
440 | ude := pl.DetectedIdentifications.Items[j] as TUD2IdentificationEntry; |
||
441 | ude.GetIdNames(outSL); |
||
442 | end; |
||
443 | end; |
||
444 | end; |
||
68 | daniel-mar | 445 | |
85 | daniel-mar | 446 | function TUD2.FulfilsEverySubterm(conds: TUD2TDFConditionArray; slIdNames: TStrings=nil): boolean; |
447 | begin |
||
448 | result := FulfilsEverySubterm(UD2_CondsToStr(conds), slIdNames); |
||
449 | end; |
||
450 | |||
81 | daniel-mar | 451 | function TUD2.FulfilsEverySubterm(idTerm: WideString; slIdNames: TStrings=nil): boolean; |
452 | var |
||
453 | i: integer; |
||
83 | daniel-mar | 454 | p: TUD2Plugin; |
81 | daniel-mar | 455 | cleanUpStringList: boolean; |
85 | daniel-mar | 456 | conds: TUD2TDFConditionArray; |
457 | cond: TUD2TDFCondition; |
||
458 | idName: string; |
||
81 | daniel-mar | 459 | begin |
460 | cleanUpStringList := slIdNames = nil; |
||
68 | daniel-mar | 461 | try |
81 | daniel-mar | 462 | if cleanUpStringList then |
68 | daniel-mar | 463 | begin |
81 | daniel-mar | 464 | slIdNames := TStringList.Create; |
84 | daniel-mar | 465 | GetAllDetectedIDs(slIdNames); |
81 | daniel-mar | 466 | end; |
467 | |||
85 | daniel-mar | 468 | conds := UD2P_ParseConditions(idTerm); |
469 | |||
81 | daniel-mar | 470 | result := true; |
85 | daniel-mar | 471 | for i := Low(conds) to High(conds) do |
81 | daniel-mar | 472 | begin |
85 | daniel-mar | 473 | cond := conds[i]; |
81 | daniel-mar | 474 | |
85 | daniel-mar | 475 | if cond.dynamicDataUsed then |
83 | daniel-mar | 476 | begin |
85 | daniel-mar | 477 | p := FindPluginByMethodNameOrGuid(cond.idMethodName); |
478 | if Assigned(p) then |
||
84 | daniel-mar | 479 | begin |
85 | daniel-mar | 480 | if p.InvokeDynamicCheck(cond.dynamicData) then |
83 | daniel-mar | 481 | begin |
85 | daniel-mar | 482 | // Reload the identifications |
483 | slIdNames.Clear; |
||
484 | GetAllDetectedIDs(slIdNames); |
||
83 | daniel-mar | 485 | end; |
486 | end; |
||
487 | end; |
||
488 | |||
85 | daniel-mar | 489 | idName := UD2_CondToStr(cond); |
83 | daniel-mar | 490 | |
85 | daniel-mar | 491 | if (not cond.caseSensitive and (slIdNames.IndexOf(idName) = -1)) or |
492 | (cond.caseSensitive and (IndexOf_CS(slIdNames, idName) = -1)) then |
||
68 | daniel-mar | 493 | begin |
81 | daniel-mar | 494 | result := false; |
495 | break; |
||
68 | daniel-mar | 496 | end; |
497 | end; |
||
81 | daniel-mar | 498 | finally |
499 | if cleanUpStringList and Assigned(slIdNames) then |
||
500 | slIdNames.Free; |
||
501 | end; |
||
502 | end; |
||
68 | daniel-mar | 503 | |
83 | daniel-mar | 504 | function TUD2.FindPluginByMethodNameOrGuid(idMethodName: string): TUD2Plugin; |
505 | var |
||
506 | i: integer; |
||
507 | p: TUD2Plugin; |
||
508 | begin |
||
509 | result := nil; |
||
510 | for i := 0 to LoadedPlugins.Count-1 do |
||
511 | begin |
||
512 | p := LoadedPlugins.Items[i] as TUD2Plugin; |
||
513 | |||
514 | if p.EqualsMethodNameOrGuid(idMethodName) then |
||
515 | begin |
||
516 | result := p; |
||
517 | Exit; |
||
518 | end; |
||
519 | end; |
||
520 | end; |
||
521 | |||
85 | daniel-mar | 522 | function TUD2.GetCommandList(ShortTaskName: string): TUD2CommandArray; |
81 | daniel-mar | 523 | var |
85 | daniel-mar | 524 | i, j, l: integer; |
81 | daniel-mar | 525 | slSV, slIdNames: TStrings; |
85 | daniel-mar | 526 | tmpCmds: TUD2CommandArray; |
81 | daniel-mar | 527 | begin |
85 | daniel-mar | 528 | SetLength(result, 0); |
529 | SetLength(tmpCmds, 0); |
||
530 | |||
81 | daniel-mar | 531 | slIdNames := TStringList.Create; |
532 | try |
||
84 | daniel-mar | 533 | GetAllDetectedIDs(slIdNames); |
81 | daniel-mar | 534 | |
68 | daniel-mar | 535 | slSV := TStringList.Create; |
536 | try |
||
537 | FIniFile.ReadSectionValues(ShortTaskName, slSV); |
||
81 | daniel-mar | 538 | for i := 0 to slSV.Count-1 do |
68 | daniel-mar | 539 | begin |
85 | daniel-mar | 540 | tmpCmds := CheckTerm(slSV.Strings[i], slIdNames); |
541 | for j := Low(tmpCmds) to High(tmpCmds) do |
||
542 | begin |
||
543 | l := Length(result); |
||
544 | SetLength(result, l+1); |
||
545 | result[l] := tmpCmds[j]; |
||
546 | end; |
||
68 | daniel-mar | 547 | end; |
548 | finally |
||
549 | slSV.Free; |
||
550 | end; |
||
551 | finally |
||
552 | slIdNames.Free; |
||
553 | end; |
||
554 | end; |
||
555 | |||
85 | daniel-mar | 556 | function TUD2.CheckTerm(idTermAndCmd: string; slIdNames: TStrings=nil): TUD2CommandArray; |
83 | daniel-mar | 557 | var |
558 | slIdNamesCreated: boolean; |
||
85 | daniel-mar | 559 | ent: TUD2TDFEntry; |
83 | daniel-mar | 560 | begin |
85 | daniel-mar | 561 | SetLength(result, 0); |
562 | |||
83 | daniel-mar | 563 | slIdNamesCreated := false; |
564 | try |
||
565 | if not Assigned(slIdNames) then |
||
566 | begin |
||
567 | slIdNamesCreated := true; |
||
568 | slIdNames := TStringList.Create; |
||
84 | daniel-mar | 569 | GetAllDetectedIDs(slIdNames); |
83 | daniel-mar | 570 | end; |
571 | |||
85 | daniel-mar | 572 | if not UD2P_ParseTdfLine(idTermAndCmd, ent) then Exit; |
573 | if FulfilsEverySubterm(ent.ids, slIdNames) then |
||
574 | begin |
||
575 | result := ent.commands; |
||
576 | end; |
||
83 | daniel-mar | 577 | finally |
578 | if slIdNamesCreated then slIdNames.Free; |
||
579 | end; |
||
580 | end; |
||
581 | |||
69 | daniel-mar | 582 | { TUD2PluginLoader } |
583 | |||
584 | procedure TUD2PluginLoader.Execute; |
||
585 | begin |
||
586 | inherited; |
||
587 | |||
588 | HandleDLL; |
||
589 | end; |
||
590 | |||
83 | daniel-mar | 591 | constructor TUD2PluginLoader.Create(Suspended: boolean; DLL: string; alngid: LANGID; useDynamicData: boolean; dynamicData: WideString); |
69 | daniel-mar | 592 | begin |
593 | inherited Create(Suspended); |
||
594 | dllfile := dll; |
||
595 | pl := nil; |
||
596 | Errors := TStringList.Create; |
||
597 | lngid := alngid; |
||
83 | daniel-mar | 598 | self.useDynamicData := useDynamicData; |
599 | Self.dynamicData := dynamicData; |
||
69 | daniel-mar | 600 | end; |
601 | |||
602 | destructor TUD2PluginLoader.Destroy; |
||
603 | begin |
||
604 | Errors.Free; |
||
605 | inherited; |
||
606 | end; |
||
607 | |||
70 | daniel-mar | 608 | function TUD2PluginLoader.HandleDLL: boolean; |
69 | daniel-mar | 609 | var |
610 | sIdentifier: WideString; |
||
611 | buf: array[0..cchBufferSize-1] of WideChar; |
||
612 | pluginInterfaceID: TGUID; |
||
70 | daniel-mar | 613 | dllHandle: Cardinal; |
69 | daniel-mar | 614 | fPluginInterfaceID: TFuncPluginInterfaceID; |
615 | fPluginIdentifier: TFuncPluginIdentifier; |
||
616 | fPluginNameW: TFuncPluginNameW; |
||
617 | fPluginVendorW: TFuncPluginVendorW; |
||
618 | fPluginVersionW: TFuncPluginVersionW; |
||
619 | fIdentificationMethodNameW: TFuncIdentificationMethodNameW; |
||
620 | fIdentificationStringW: TFuncIdentificationStringW; |
||
83 | daniel-mar | 621 | fDynamicIdentificationStringW: TFuncDynamicIdentificationStringW; |
69 | daniel-mar | 622 | fCheckLicense: TFuncCheckLicense; |
70 | daniel-mar | 623 | fDescribeOwnStatusCodeW: TFuncDescribeOwnStatusCodeW; |
69 | daniel-mar | 624 | statusCode: UD2_STATUS; |
625 | i: integer; |
||
626 | starttime, endtime, time: cardinal; |
||
82 | daniel-mar | 627 | bakErrorMode: DWORD; |
628 | err: DWORD; |
||
70 | daniel-mar | 629 | |
630 | function _ErrorLookup(statusCode: UD2_STATUS): WideString; |
||
631 | var |
||
632 | ret: BOOL; |
||
83 | daniel-mar | 633 | buf: array[0..cchBufferSize-1] of WideChar; |
70 | daniel-mar | 634 | begin |
82 | daniel-mar | 635 | if Assigned(fDescribeOwnStatusCodeW) then |
70 | daniel-mar | 636 | begin |
82 | daniel-mar | 637 | ZeroMemory(@buf, cchBufferSize); |
638 | ret := fDescribeOwnStatusCodeW(@buf, cchBufferSize, statusCode, lngID); |
||
639 | if ret then |
||
640 | begin |
||
641 | result := PWideChar(@buf); |
||
642 | Exit; |
||
643 | end; |
||
70 | daniel-mar | 644 | end; |
645 | result := TUD2.GenericErrorLookup(statusCode); |
||
646 | end; |
||
647 | |||
82 | daniel-mar | 648 | function _ApplyCompatibilityGUID: boolean; |
649 | var |
||
650 | iniConfig: TIniFile; |
||
651 | sOverrideGUID: string; |
||
652 | sPluginConfigFile: string; |
||
69 | daniel-mar | 653 | begin |
82 | daniel-mar | 654 | result := false; |
69 | daniel-mar | 655 | sPluginConfigFile := ChangeFileExt(dllFile, '.ini'); |
656 | if FileExists(sPluginConfigFile) then |
||
657 | begin |
||
658 | iniConfig := TIniFile.Create(sPluginConfigFile); |
||
659 | try |
||
660 | sOverrideGUID := iniConfig.ReadString('Compatibility', 'OverrideGUID', ''); |
||
661 | if sOverrideGUID <> '' then |
||
662 | begin |
||
663 | pl.PluginGUID := StringToGUID(sOverrideGUID); |
||
82 | daniel-mar | 664 | result := true; |
69 | daniel-mar | 665 | end; |
666 | finally |
||
667 | iniConfig.Free; |
||
668 | end; |
||
669 | end; |
||
82 | daniel-mar | 670 | end; |
69 | daniel-mar | 671 | |
82 | daniel-mar | 672 | function _AutoOSNotSupportedMode: integer; |
673 | var |
||
674 | iniConfig: TIniFile; |
||
675 | sPluginConfigFile: string; |
||
676 | begin |
||
677 | result := 0; |
||
678 | sPluginConfigFile := ChangeFileExt(dllFile, '.ini'); |
||
679 | if FileExists(sPluginConfigFile) then |
||
69 | daniel-mar | 680 | begin |
82 | daniel-mar | 681 | iniConfig := TIniFile.Create(sPluginConfigFile); |
682 | try |
||
683 | result := iniConfig.ReadInteger('Compatibility', 'AutoOSNotSupported', 0); |
||
684 | finally |
||
685 | iniConfig.Free; |
||
69 | daniel-mar | 686 | end; |
687 | end; |
||
82 | daniel-mar | 688 | end; |
69 | daniel-mar | 689 | |
82 | daniel-mar | 690 | procedure _OverwriteStatusToOSNotSupported; |
691 | begin |
||
692 | pl := TUD2Plugin.Create; |
||
693 | pl.PluginDLL := dllFile; |
||
694 | statusCode := UD2_STATUS_NOTAVAIL_OS_NOT_SUPPORTED; |
||
695 | pl.IdentificationProcedureStatusCode := statusCode; |
||
696 | pl.IdentificationProcedureStatusCodeDescribed := _ErrorLookup(statusCode); |
||
697 | (* |
||
698 | if not _ApplyCompatibilityGUID then |
||
69 | daniel-mar | 699 | begin |
82 | daniel-mar | 700 | CreateGUID(pl.PluginGUID); // to avoid the "double GUID" error |
69 | daniel-mar | 701 | end; |
82 | daniel-mar | 702 | *) |
703 | pl.OSNotSupportedEnforced := true; // to avoid the "double GUID" error |
||
704 | result := true; |
||
705 | end; |
||
69 | daniel-mar | 706 | |
82 | daniel-mar | 707 | resourcestring |
708 | LNG_DLL_NOT_LOADED = 'Plugin DLL "%s" could not be loaded: %s'; |
||
709 | LNG_METHOD_NOT_FOUND = 'Method "%s" not found in plugin "%s". The DLL is probably not a valid plugin DLL.'; |
||
710 | LNG_INVALID_PLUGIN = 'The plugin "%s" is not a valid plugin for this application.'; |
||
711 | LNG_METHOD_FAILURE = 'Error "%s" at method "%s" of plugin "%s".'; |
||
712 | LNG_EXCEPTION = 'Fatal error while loading "%s" (%s: %s)'; |
||
713 | begin |
||
714 | result := false; |
||
715 | startTime := GetTickCount; |
||
69 | daniel-mar | 716 | |
82 | daniel-mar | 717 | try |
718 | bakErrorMode := 0; |
||
719 | UD2_SetThreadErrorMode(SEM_FAILCRITICALERRORS, Pointer(bakErrorMode)); |
||
720 | try |
||
721 | dllHandle := LoadLibrary(PChar(dllFile)); |
||
722 | if dllHandle = 0 then |
||
723 | begin |
||
724 | err := GetLastError; |
||
69 | daniel-mar | 725 | |
82 | daniel-mar | 726 | if ((_AutoOSNotSupportedMode = 1) and ((err = ERROR_DLL_NOT_FOUND) or (err = ERROR_PROC_NOT_FOUND))) or |
727 | (_AutoOSNotSupportedMode >= 2) then |
||
728 | begin |
||
729 | _OverwriteStatusToOSNotSupported; |
||
730 | Exit; |
||
731 | end; |
||
69 | daniel-mar | 732 | |
82 | daniel-mar | 733 | Errors.Add(Format(LNG_DLL_NOT_LOADED, [dllFile, SysErrorMessage(err)])); |
734 | Exit; |
||
735 | end; |
||
736 | try |
||
737 | @fPluginInterfaceID := GetProcAddress(dllHandle, mnPluginInterfaceID); |
||
738 | if not Assigned(fPluginInterfaceID) then |
||
739 | begin |
||
740 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginInterfaceID, dllFile])); |
||
741 | Exit; |
||
742 | end; |
||
743 | pluginInterfaceID := fPluginInterfaceID(); |
||
744 | if not IsEqualGUID(pluginInterfaceID, GUID_USERDETECT2_IDPLUGIN_V1) then |
||
745 | begin |
||
746 | Errors.Add(Format(LNG_INVALID_PLUGIN, [dllFile])); |
||
747 | Exit; |
||
748 | end; |
||
69 | daniel-mar | 749 | |
83 | daniel-mar | 750 | fDynamicIdentificationStringW := nil; |
751 | fIdentificationStringW := nil; |
||
752 | if useDynamicData then |
||
69 | daniel-mar | 753 | begin |
83 | daniel-mar | 754 | @fDynamicIdentificationStringW := GetProcAddress(dllHandle, mnDynamicIdentificationStringW); |
755 | if not Assigned(fDynamicIdentificationStringW) then |
||
756 | begin |
||
757 | // TODO xxx: Darf hier ein fataler Fehler entstehen, obwohl dieses Szenario nur durch die INI file auftreten kann? |
||
758 | // TODO (allgemein): In der Modulübersicht soll auch gezeigt werden, ob dieses Modul dynamischen Content erlaubt. |
||
759 | // TODO (allgemein): doku |
||
760 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnDynamicIdentificationStringW, dllFile])); |
||
761 | Exit; |
||
762 | end; |
||
763 | end |
||
764 | else |
||
765 | begin |
||
766 | @fIdentificationStringW := GetProcAddress(dllHandle, mnIdentificationStringW); |
||
767 | if not Assigned(fIdentificationStringW) then |
||
768 | begin |
||
769 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnIdentificationStringW, dllFile])); |
||
770 | Exit; |
||
771 | end; |
||
69 | daniel-mar | 772 | end; |
82 | daniel-mar | 773 | |
774 | @fPluginNameW := GetProcAddress(dllHandle, mnPluginNameW); |
||
775 | if not Assigned(fPluginNameW) then |
||
776 | begin |
||
777 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginNameW, dllFile])); |
||
778 | Exit; |
||
779 | end; |
||
780 | |||
781 | @fPluginVendorW := GetProcAddress(dllHandle, mnPluginVendorW); |
||
782 | if not Assigned(fPluginVendorW) then |
||
783 | begin |
||
784 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginVendorW, dllFile])); |
||
785 | Exit; |
||
786 | end; |
||
787 | |||
788 | @fPluginVersionW := GetProcAddress(dllHandle, mnPluginVersionW); |
||
789 | if not Assigned(fPluginVersionW) then |
||
790 | begin |
||
791 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginVersionW, dllFile])); |
||
792 | Exit; |
||
793 | end; |
||
794 | |||
795 | @fCheckLicense := GetProcAddress(dllHandle, mnCheckLicense); |
||
796 | if not Assigned(fCheckLicense) then |
||
797 | begin |
||
798 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnCheckLicense, dllFile])); |
||
799 | Exit; |
||
800 | end; |
||
801 | |||
802 | @fIdentificationMethodNameW := GetProcAddress(dllHandle, mnIdentificationMethodNameW); |
||
803 | if not Assigned(fIdentificationMethodNameW) then |
||
804 | begin |
||
805 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnIdentificationMethodNameW, dllFile])); |
||
806 | Exit; |
||
807 | end; |
||
808 | |||
809 | @fDescribeOwnStatusCodeW := GetProcAddress(dllHandle, mnDescribeOwnStatusCodeW); |
||
810 | if not Assigned(fDescribeOwnStatusCodeW) then |
||
811 | begin |
||
812 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnDescribeOwnStatusCodeW, dllFile])); |
||
813 | Exit; |
||
814 | end; |
||
815 | |||
816 | pl := TUD2Plugin.Create; |
||
817 | pl.PluginDLL := dllFile; |
||
818 | |||
819 | if not _ApplyCompatibilityGUID then |
||
820 | begin |
||
821 | @fPluginIdentifier := GetProcAddress(dllHandle, mnPluginIdentifier); |
||
822 | if not Assigned(fPluginIdentifier) then |
||
823 | begin |
||
824 | Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginIdentifier, dllFile])); |
||
825 | Exit; |
||
826 | end; |
||
827 | pl.PluginGUID := fPluginIdentifier(); |
||
828 | end; |
||
829 | |||
830 | statusCode := fCheckLicense(nil); |
||
831 | if statusCode.wCategory = UD2_STATUSCAT_FAILED then |
||
832 | begin |
||
833 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnCheckLicense, dllFile])); |
||
834 | Exit; |
||
835 | end; |
||
836 | |||
837 | ZeroMemory(@buf, cchBufferSize); |
||
838 | statusCode := fPluginNameW(@buf, cchBufferSize, lngID); |
||
839 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then pl.PluginName := PWideChar(@buf) |
||
840 | else if statusCode.wCategory = UD2_STATUSCAT_NOT_AVAIL then pl.PluginName := '' |
||
841 | else |
||
842 | begin |
||
843 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginNameW, dllFile])); |
||
844 | Exit; |
||
845 | end; |
||
846 | |||
847 | ZeroMemory(@buf, cchBufferSize); |
||
848 | statusCode := fPluginVendorW(@buf, cchBufferSize, lngID); |
||
849 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then pl.PluginVendor := PWideChar(@buf) |
||
850 | else if statusCode.wCategory = UD2_STATUSCAT_NOT_AVAIL then pl.PluginVendor := '' |
||
851 | else |
||
852 | begin |
||
853 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginVendorW, dllFile])); |
||
854 | Exit; |
||
855 | end; |
||
856 | |||
857 | ZeroMemory(@buf, cchBufferSize); |
||
858 | statusCode := fPluginVersionW(@buf, cchBufferSize, lngID); |
||
859 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then pl.PluginVersion := PWideChar(@buf) |
||
860 | else if statusCode.wCategory = UD2_STATUSCAT_NOT_AVAIL then pl.PluginVersion := '' |
||
861 | else |
||
862 | begin |
||
863 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginVersionW, dllFile])); |
||
864 | Exit; |
||
865 | end; |
||
866 | |||
867 | ZeroMemory(@buf, cchBufferSize); |
||
868 | statusCode := fIdentificationMethodNameW(@buf, cchBufferSize); |
||
869 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then pl.IdentificationMethodName := PWideChar(@buf) |
||
870 | else if statusCode.wCategory = UD2_STATUSCAT_NOT_AVAIL then pl.IdentificationMethodName := '' |
||
871 | else |
||
872 | begin |
||
873 | Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnIdentificationMethodNameW, dllFile])); |
||
874 | Exit; |
||
875 | end; |
||
876 | |||
877 | ZeroMemory(@buf, cchBufferSize); |
||
878 | 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) |
||
83 | daniel-mar | 879 | if useDynamicData then |
880 | begin |
||
881 | statusCode := fDynamicIdentificationStringW(@buf, cchBufferSize, PWideChar(dynamicData)); |
||
882 | end |
||
883 | else |
||
884 | begin |
||
885 | statusCode := fIdentificationStringW(@buf, cchBufferSize); |
||
886 | end; |
||
82 | daniel-mar | 887 | pl.IdentificationProcedureStatusCode := statusCode; |
888 | pl.IdentificationProcedureStatusCodeDescribed := _ErrorLookup(statusCode); |
||
889 | if statusCode.wCategory = UD2_STATUSCAT_SUCCESS then |
||
890 | begin |
||
891 | sIdentifier := PWideChar(@buf); |
||
892 | if UD2_STATUS_Equal(statusCode, UD2_STATUS_OK_MULTILINE, false) then |
||
893 | begin |
||
894 | // Multiple identifiers (e.g. multiple MAC addresses are delimited via UD2_MULTIPLE_ITEMS_DELIMITER) |
||
83 | daniel-mar | 895 | SetLength(ResultIdentifiers, 0); |
896 | ResultIdentifiers := SplitString(UD2_MULTIPLE_ITEMS_DELIMITER, sIdentifier); |
||
897 | for i := Low(ResultIdentifiers) to High(ResultIdentifiers) do |
||
82 | daniel-mar | 898 | begin |
83 | daniel-mar | 899 | pl.AddIdentification(ResultIdentifiers[i]); |
82 | daniel-mar | 900 | end; |
901 | end |
||
902 | else |
||
903 | begin |
||
904 | pl.AddIdentification(sIdentifier); |
||
83 | daniel-mar | 905 | |
906 | SetLength(ResultIdentifiers, 1); |
||
907 | ResultIdentifiers[0] := sIdentifier; |
||
82 | daniel-mar | 908 | end; |
909 | end |
||
910 | else if statusCode.wCategory <> UD2_STATUSCAT_NOT_AVAIL then |
||
911 | begin |
||
912 | if _AutoOSNotSupportedMode >= 3 then |
||
913 | begin |
||
914 | _OverwriteStatusToOSNotSupported; |
||
915 | Exit; |
||
916 | end; |
||
917 | |||
918 | // Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnIdentificationStringW, dllFile])); |
||
919 | Errors.Add(Format(LNG_METHOD_FAILURE, [pl.IdentificationProcedureStatusCodeDescribed, mnIdentificationStringW, dllFile])); |
||
920 | Exit; |
||
921 | end; |
||
922 | |||
923 | result := true; |
||
924 | finally |
||
925 | if not result and Assigned(pl) then FreeAndNil(pl); |
||
926 | FreeLibrary(dllHandle); |
||
927 | end; |
||
928 | finally |
||
929 | UD2_SetThreadErrorMode(bakErrorMode, nil); |
||
930 | |||
931 | if result then |
||
69 | daniel-mar | 932 | begin |
82 | daniel-mar | 933 | endtime := GetTickCount; |
934 | time := endtime - starttime; |
||
935 | if endtime < starttime then time := High(Cardinal) - time; |
||
936 | pl.time := time; |
||
69 | daniel-mar | 937 | end; |
82 | daniel-mar | 938 | end; |
939 | except |
||
940 | // TODO: when an exception happens in a cdecl DLL, then this code is somehow not |
||
941 | // executed. Probably the memory is corrupted. Anyway, a cdecl DLL shall NEVER |
||
942 | // raise an Exception. |
||
943 | on E: Exception do |
||
69 | daniel-mar | 944 | begin |
82 | daniel-mar | 945 | Errors.Add(Format(LNG_EXCEPTION, [dllFile, E.ClassName, E.Message])); |
69 | daniel-mar | 946 | Exit; |
947 | end; |
||
948 | end; |
||
949 | end; |
||
950 | |||
68 | daniel-mar | 951 | end. |