Subversion Repositories userdetect2

Rev

Rev 90 | Rev 92 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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