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