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