Subversion Repositories userdetect2

Rev

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.