Subversion Repositories userdetect2

Rev

Rev 69 | Rev 71 | 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
70 daniel-mar 12
  Windows, SysUtils, Classes, IniFiles, Contnrs, Dialogs, UD2_PluginIntf;
68 daniel-mar 13
 
14
const
69 daniel-mar 15
  cchBufferSize = 32768;
68 daniel-mar 16
 
17
type
18
  TUD2Plugin = class(TObject)
19
  protected
20
    FDetectedIdentifications: TObjectList{<TUD2IdentificationEntry>};
21
  public
22
    PluginDLL: string;
23
    PluginGUID: TGUID;
24
    PluginName: WideString;
25
    PluginVendor: WideString;
26
    PluginVersion: WideString;
27
    IdentificationMethodName: WideString;
70 daniel-mar 28
 
29
    // ONLY contains the non-failure status code of IdentificationStringW
30
    IdentificationProcedureStatusCode: UD2_STATUS;
31
    IdentificationProcedureStatusCodeDescribed: WideString;
32
 
69 daniel-mar 33
    Time: Cardinal;
68 daniel-mar 34
    function PluginGUIDString: string;
35
    property DetectedIdentifications: TObjectList{<TUD2IdentificationEntry>}
36
      read FDetectedIdentifications;
37
    destructor Destroy; override;
38
    constructor Create;
39
    procedure AddIdentification(IdStr: WideString);
40
  end;
41
 
42
  TUD2IdentificationEntry = class(TObject)
43
  private
44
    FIdentificationString: WideString;
45
    FPlugin: TUD2Plugin;
46
  public
47
    property IdentificationString: WideString read FIdentificationString;
48
    property Plugin: TUD2Plugin read FPlugin;
49
    function GetPrimaryIdName: WideString;
50
    procedure GetIdNames(sl: TStrings);
51
    constructor Create(AIdentificationString: WideString; APlugin: TUD2Plugin);
52
  end;
53
 
54
  TUD2 = class(TObject)
55
  private
70 daniel-mar 56
    {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID}
68 daniel-mar 57
    FGUIDLookup: TStrings;
70 daniel-mar 58
    {$ENDIF}
68 daniel-mar 59
  protected
60
    FLoadedPlugins: TObjectList{<TUD2Plugin>};
61
    FIniFile: TMemIniFile;
62
    FErrors: TStrings;
63
    FIniFileName: string;
64
  public
65
    property IniFileName: string read FIniFileName;
66
    property Errors: TStrings read FErrors;
67
    property LoadedPlugins: TObjectList{<TUD2Plugin>} read FLoadedPlugins;
68
    property IniFile: TMemIniFile read FIniFile;
69
    procedure GetCommandList(ShortTaskName: string; outSL: TStrings);
70
    procedure HandlePluginDir(APluginDir: string);
71
    procedure GetTaskListing(outSL: TStrings);
72
    constructor Create(AIniFileName: string);
73
    destructor Destroy; override;
74
    function TaskExists(ShortTaskName: string): boolean;
75
    function ReadMetatagString(ShortTaskName, MetatagName: string;
76
      DefaultVal: string): string;
77
    function ReadMetatagBool(ShortTaskName, MetatagName: string;
78
      DefaultVal: string): boolean;
79
    function GetTaskName(AShortTaskName: string): string;
70 daniel-mar 80
    class function GenericErrorLookup(dwStatus: UD2_STATUS): string;
68 daniel-mar 81
  end;
82
 
83
implementation
84
 
85
uses
70 daniel-mar 86
  UD2_Utils;
68 daniel-mar 87
 
69 daniel-mar 88
type
89
  TUD2PluginLoader = class(TThread)
90
  protected
91
    dllFile: string;
92
    lngID: LANGID;
93
    procedure Execute; override;
70 daniel-mar 94
    function HandleDLL: boolean;
69 daniel-mar 95
  public
96
    pl: TUD2Plugin;
97
    Errors: TStringList;
98
    constructor Create(Suspended: boolean; DLL: string; alngid: LANGID);
99
    destructor Destroy; override;
100
  end;
101
 
70 daniel-mar 102
class function TUD2.GenericErrorLookup(dwStatus: UD2_STATUS): string;
68 daniel-mar 103
resourcestring
69 daniel-mar 104
  LNG_STATUS_OK_UNSPECIFIED            = 'Unspecified generic success';
105
  LNG_STATUS_OK_SINGLELINE             = 'Operation successful; one identifier returned';
106
  LNG_STATUS_OK_MULTILINE              = 'Operation successful; multiple identifiers returned';
107
 
108
  LNG_STATUS_NOTAVAIL_UNSPECIFIED      = 'Unspecified generic "not available" status';
109
  LNG_STATUS_NOTAVAIL_OS_NOT_SUPPORTED = 'Operating system not supported';
110
  LNG_STATUS_NOTAVAIL_HW_NOT_SUPPORTED = 'Hardware not supported';
111
  LNG_STATUS_NOTAVAIL_NO_ENTITIES      = 'No entities to identify';
112
  LNG_STATUS_NOTAVAIL_API_CALL_FAILURE = 'An API call failed';
113
 
114
  LNG_STATUS_ERROR_UNSPECIFIED         = 'Unspecified generic error';
115
  LNG_STATUS_ERROR_BUFFER_TOO_SMALL    = 'The provided buffer is too small!';
116
  LNG_STATUS_ERROR_INVALID_ARGS        = 'The function received invalid arguments!';
117
  LNG_STATUS_ERROR_PLUGIN_NOT_LICENSED = 'The plugin is not licensed';
118
 
119
  LNG_UNKNOWN_SUCCESS                  = 'Unknown "success" status code %s';
120
  LNG_UNKNOWN_NOTAVAIL                 = 'Unknown "not available" status code %s';
121
  LNG_UNKNOWN_FAILED                   = 'Unknown "failed" status code %s';
122
  LNG_UNKNOWN_STATUS                   = 'Unknown status code with unexpected category: %s';
68 daniel-mar 123
begin
69 daniel-mar 124
       if dwStatus = UD2_STATUS_OK_UNSPECIFIED            then result := LNG_STATUS_OK_UNSPECIFIED
125
  else if dwStatus = UD2_STATUS_OK_SINGLELINE             then result := LNG_STATUS_OK_SINGLELINE
126
  else if dwStatus = UD2_STATUS_OK_MULTILINE              then result := LNG_STATUS_OK_MULTILINE
127
 
128
  else if dwStatus = UD2_STATUS_NOTAVAIL_UNSPECIFIED      then result := LNG_STATUS_NOTAVAIL_UNSPECIFIED
129
  else if dwStatus = UD2_STATUS_NOTAVAIL_OS_NOT_SUPPORTED then result := LNG_STATUS_NOTAVAIL_OS_NOT_SUPPORTED
130
  else if dwStatus = UD2_STATUS_NOTAVAIL_HW_NOT_SUPPORTED then result := LNG_STATUS_NOTAVAIL_HW_NOT_SUPPORTED
131
  else if dwStatus = UD2_STATUS_NOTAVAIL_NO_ENTITIES      then result := LNG_STATUS_NOTAVAIL_NO_ENTITIES
132
  else if dwStatus = UD2_STATUS_NOTAVAIL_API_CALL_FAILURE then result := LNG_STATUS_NOTAVAIL_API_CALL_FAILURE
133
 
134
  else if dwStatus = UD2_STATUS_ERROR_UNSPECIFIED         then result := LNG_STATUS_ERROR_UNSPECIFIED
135
  else if dwStatus = UD2_STATUS_ERROR_BUFFER_TOO_SMALL    then result := LNG_STATUS_ERROR_BUFFER_TOO_SMALL
136
  else if dwStatus = UD2_STATUS_ERROR_INVALID_ARGS        then result := LNG_STATUS_ERROR_INVALID_ARGS
137
  else if dwStatus = UD2_STATUS_ERROR_PLUGIN_NOT_LICENSED then result := LNG_STATUS_ERROR_PLUGIN_NOT_LICENSED
138
 
139
  else if UD2_STATUS_Successful(dwStatus) then result := Format(LNG_UNKNOWN_SUCCESS,  [UD2_STATUS_FormatStatusCode(dwStatus)])
140
  else if UD2_STATUS_NotAvail(dwStatus)   then result := Format(LNG_UNKNOWN_NOTAVAIL, [UD2_STATUS_FormatStatusCode(dwStatus)])
141
  else if UD2_STATUS_Failed(dwStatus)     then result := Format(LNG_UNKNOWN_FAILED,   [UD2_STATUS_FormatStatusCode(dwStatus)])
142
  else                                         result := Format(LNG_UNKNOWN_STATUS,   [UD2_STATUS_FormatStatusCode(dwStatus)]);
68 daniel-mar 143
end;
144
 
145
{ TUD2Plugin }
146
 
147
function TUD2Plugin.PluginGUIDString: string;
148
begin
149
  result := UpperCase(GUIDToString(PluginGUID));
150
end;
151
 
152
procedure TUD2Plugin.AddIdentification(IdStr: WideString);
153
begin
154
  DetectedIdentifications.Add(TUD2IdentificationEntry.Create(IdStr, Self))
155
end;
156
 
157
destructor TUD2Plugin.Destroy;
158
begin
159
  DetectedIdentifications.Free;
160
  inherited;
161
end;
162
 
163
constructor TUD2Plugin.Create;
164
begin
165
  inherited Create;
166
  FDetectedIdentifications := TObjectList{<TUD2IdentificationEntry>}.Create(true);
167
end;
168
 
169
{ TUD2IdentificationEntry }
170
 
171
function TUD2IdentificationEntry.GetPrimaryIdName: WideString;
172
begin
173
  result := Plugin.IdentificationMethodName+':'+IdentificationString;
174
end;
175
 
176
procedure TUD2IdentificationEntry.GetIdNames(sl: TStrings);
177
begin
178
  sl.Add(GetPrimaryIdName);
179
  sl.Add(UpperCase(Plugin.IdentificationMethodName)+':'+IdentificationString);
180
  sl.Add(LowerCase(Plugin.IdentificationMethodName)+':'+IdentificationString);
181
  sl.Add(UpperCase(Plugin.PluginGUIDString)+':'+IdentificationString);
182
  sl.Add(LowerCase(Plugin.PluginGUIDString)+':'+IdentificationString);
183
end;
184
 
185
constructor TUD2IdentificationEntry.Create(AIdentificationString: WideString;
186
  APlugin: TUD2Plugin);
187
begin
188
  inherited Create;
189
  FIdentificationString := AIdentificationString;
190
  FPlugin := APlugin;
191
end;
192
 
193
{ TUD2 }
194
 
69 daniel-mar 195
procedure TUD2.HandlePluginDir(APluginDir: string);
196
Var
197
  SR: TSearchRec;
198
  path: string;
70 daniel-mar 199
  pluginLoader: TUD2PluginLoader;
69 daniel-mar 200
  tob: TObjectList;
68 daniel-mar 201
  i: integer;
70 daniel-mar 202
  {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID}
203
  sPluginID, prevDLL: string;
204
  {$ENDIF}
69 daniel-mar 205
  lngid: LANGID;
68 daniel-mar 206
resourcestring
207
  LNG_PLUGINS_SAME_GUID = 'Attention: The plugin "%s" and the plugin "%s" have the same identification GUID. The latter will not be loaded.';
208
begin
69 daniel-mar 209
  tob := TObjectList.Create;
68 daniel-mar 210
  try
69 daniel-mar 211
    tob.OwnsObjects := false;
68 daniel-mar 212
 
69 daniel-mar 213
    lngID := GetSystemDefaultLangID;
68 daniel-mar 214
 
69 daniel-mar 215
    path := IncludeTrailingPathDelimiter(APluginDir);
216
    if FindFirst(path + '*.dll', 0, SR) = 0 then
68 daniel-mar 217
    begin
218
      try
69 daniel-mar 219
        repeat
220
          try
221
            tob.Add(TUD2PluginLoader.Create(false, path+sr.Name, lngid));
222
          except
223
            on E: Exception do
224
            begin
225
              MessageDlg(E.Message, mtError, [mbOK], 0);
226
            end;
227
          end;
228
        until FindNext(SR) <> 0;
68 daniel-mar 229
      finally
69 daniel-mar 230
        FindClose(SR);
68 daniel-mar 231
      end;
232
    end;
233
 
69 daniel-mar 234
    for i := 0 to tob.count-1 do
68 daniel-mar 235
    begin
70 daniel-mar 236
      pluginLoader := tob.items[i] as TUD2PluginLoader;
237
      pluginLoader.WaitFor;
238
      Errors.AddStrings(pluginLoader.Errors);
239
      {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID}
240
      if Assigned(pluginLoader.pl) then
68 daniel-mar 241
      begin
70 daniel-mar 242
        sPluginID := GUIDToString(pluginLoader.pl.PluginGUID);
243
        prevDLL := FGUIDLookup.Values[sPluginID];
244
        if (prevDLL <> '') and (prevDLL <> pluginLoader.pl.PluginDLL) then
69 daniel-mar 245
        begin
70 daniel-mar 246
          Errors.Add(Format(LNG_PLUGINS_SAME_GUID, [prevDLL, pluginLoader.pl.PluginDLL]));
247
          pluginLoader.pl.Free;
69 daniel-mar 248
        end
249
        else
250
        begin
70 daniel-mar 251
          FGUIDLookup.Values[sPluginID] := pluginLoader.pl.PluginDLL;
252
          LoadedPlugins.Add(pluginLoader.pl);
69 daniel-mar 253
        end;
68 daniel-mar 254
      end;
70 daniel-mar 255
      {$ENDIF}
256
      pluginLoader.Free;
68 daniel-mar 257
    end;
258
  finally
69 daniel-mar 259
    tob.free;
68 daniel-mar 260
  end;
261
end;
262
 
263
destructor TUD2.Destroy;
264
begin
265
  FIniFile.Free;
266
  FLoadedPlugins.Free;
70 daniel-mar 267
  {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID}
68 daniel-mar 268
  FGUIDLookup.Free;
70 daniel-mar 269
  {$ENDIF}
68 daniel-mar 270
  FErrors.Free;
271
end;
272
 
273
constructor TUD2.Create(AIniFileName: string);
274
begin
275
  FIniFileName := AIniFileName;
276
  FLoadedPlugins := TObjectList{<TUD2Plugin>}.Create(true);
277
  FIniFile := TMemIniFile.Create(IniFileName);
70 daniel-mar 278
  {$IFDEF CHECK_FOR_SAME_PLUGIN_GUID}
68 daniel-mar 279
  FGUIDLookup := TStringList.Create;
70 daniel-mar 280
  {$ENDIF}
68 daniel-mar 281
  FErrors := TStringList.Create;
282
end;
283
 
284
function TUD2.GetTaskName(AShortTaskName: string): string;
69 daniel-mar 285
resourcestring
286
  LNG_NO_DESCRIPTION = '(%s)';
68 daniel-mar 287
begin
69 daniel-mar 288
  result := FIniFile.ReadString(AShortTaskName, 'Description', Format(LNG_NO_DESCRIPTION, [AShortTaskName]));
68 daniel-mar 289
end;
290
 
291
procedure TUD2.GetTaskListing(outSL: TStrings);
292
var
293
  sl: TStringList;
294
  i: integer;
295
  desc: string;
296
begin
297
  sl := TStringList.Create;
298
  try
299
    FIniFile.ReadSections(sl);
300
    for i := 0 to sl.Count-1 do
301
    begin
302
      desc := GetTaskName(sl.Strings[i]);
303
      outSL.Values[sl.Strings[i]] := desc;
304
    end;
305
  finally
306
    sl.Free;
307
  end;
308
end;
309
 
310
function TUD2.TaskExists(ShortTaskName: string): boolean;
311
begin
312
  result := FIniFile.SectionExists(ShortTaskName);
313
end;
314
 
315
function TUD2.ReadMetatagString(ShortTaskName, MetatagName: string;
316
  DefaultVal: string): string;
317
begin
318
  result := IniFile.ReadString(ShortTaskName, MetatagName, DefaultVal);
319
end;
320
 
321
function TUD2.ReadMetatagBool(ShortTaskName, MetatagName: string;
322
  DefaultVal: string): boolean;
323
begin
324
  // DefaultVal is a string, because we want to allow an empty string, in case the
325
  // user wishes an Exception in case the string is not a valid boolean string
326
  result := BetterInterpreteBool(IniFile.ReadString(ShortTaskName, MetatagName, DefaultVal));
327
end;
328
 
329
(*
330
 
331
NAMING EXAMPLE: ComputerName:ABC&&User:John=calc.exe
332
 
333
        idTerm:       ComputerName:ABC&&User:John
334
        idName:       ComputerName:ABC
335
        IdMethodName: ComputerName
336
        IdStr         ABC
337
        cmd:          calc.exe
338
 
339
*)
340
 
341
procedure TUD2.GetCommandList(ShortTaskName: string; outSL: TStrings);
342
var
343
  i, j: integer;
344
  cmd: string;
345
  idTerm, idName: WideString;
346
  slSV, slIdNames: TStrings;
347
  x: TArrayOfString;
348
  nameVal: TArrayOfString;
349
  FulfilsEverySubterm: boolean;
350
  pl: TUD2Plugin;
351
  ude: TUD2IdentificationEntry;
352
begin
353
  SetLength(x, 0);
354
  SetLength(nameVal, 0);
355
 
356
  slIdNames := TStringList.Create;
357
  try
358
    for i := 0 to LoadedPlugins.Count-1 do
359
    begin
360
      pl := LoadedPlugins.Items[i] as TUD2Plugin;
361
      for j := 0 to pl.DetectedIdentifications.Count-1 do
362
      begin
363
        ude := pl.DetectedIdentifications.Items[j] as TUD2IdentificationEntry;
364
        ude.GetIdNames(slIdNames);
365
      end;
366
    end;
367
 
368
    slSV := TStringList.Create;
369
    try
370
      FIniFile.ReadSectionValues(ShortTaskName, slSV);
371
      for j := 0 to slSV.Count-1 do
372
      begin
373
        // We are doing the interpretation of the line ourselves, because
374
        // TStringList.Values[] would not allow multiple command lines with the
375
        // same key (idTerm)
376
        nameVal := SplitString('=', slSV.Strings[j]);
377
        idTerm := nameVal[0];
378
        cmd    := nameVal[1];
379
 
380
        if Pos(':', idTerm) = 0 then Continue;
381
        x := SplitString('&&', idTerm);
382
        FulfilsEverySubterm := true;
383
        for i := Low(x) to High(x) do
384
        begin
385
          idName := x[i];
386
 
387
          if slIdNames.IndexOf(idName) = -1 then
388
          begin
389
            FulfilsEverySubterm := false;
390
            break;
391
          end;
392
        end;
393
 
394
        if FulfilsEverySubterm then outSL.Add(cmd);
395
      end;
396
    finally
397
      slSV.Free;
398
    end;
399
  finally
400
    slIdNames.Free;
401
  end;
402
end;
403
 
69 daniel-mar 404
{ TUD2PluginLoader }
405
 
406
procedure TUD2PluginLoader.Execute;
407
begin
408
  inherited;
409
 
410
  HandleDLL;
411
end;
412
 
413
constructor TUD2PluginLoader.Create(Suspended: boolean; DLL: string; alngid: LANGID);
414
begin
415
  inherited Create(Suspended);
416
  dllfile := dll;
417
  pl := nil;
418
  Errors := TStringList.Create;
419
  lngid := alngid;
420
end;
421
 
422
destructor TUD2PluginLoader.Destroy;
423
begin
424
  Errors.Free;
425
  inherited;
426
end;
427
 
70 daniel-mar 428
function TUD2PluginLoader.HandleDLL: boolean;
69 daniel-mar 429
var
430
  sIdentifier: WideString;
431
  sIdentifiers: TArrayOfString;
432
  buf: array[0..cchBufferSize-1] of WideChar;
433
  sPluginConfigFile: string;
434
  iniConfig: TINIFile;
435
  sOverrideGUID: string;
436
  pluginIDfound: boolean;
437
  pluginInterfaceID: TGUID;
70 daniel-mar 438
  dllHandle: Cardinal;
69 daniel-mar 439
  fPluginInterfaceID: TFuncPluginInterfaceID;
440
  fPluginIdentifier: TFuncPluginIdentifier;
441
  fPluginNameW: TFuncPluginNameW;
442
  fPluginVendorW: TFuncPluginVendorW;
443
  fPluginVersionW: TFuncPluginVersionW;
444
  fIdentificationMethodNameW: TFuncIdentificationMethodNameW;
445
  fIdentificationStringW: TFuncIdentificationStringW;
446
  fCheckLicense: TFuncCheckLicense;
70 daniel-mar 447
  fDescribeOwnStatusCodeW: TFuncDescribeOwnStatusCodeW;
69 daniel-mar 448
  statusCode: UD2_STATUS;
449
  i: integer;
450
  starttime, endtime, time: cardinal;
70 daniel-mar 451
 
452
  function _ErrorLookup(statusCode: UD2_STATUS): WideString;
453
  var
454
    ret: BOOL;
455
  begin
456
    ret := fDescribeOwnStatusCodeW(@buf, cchBufferSize, statusCode, lngID);
457
    if ret then
458
    begin
459
      result := PWideChar(@buf);
460
      Exit;
461
    end;
462
    result := TUD2.GenericErrorLookup(statusCode);
463
  end;
464
 
69 daniel-mar 465
resourcestring
466
  LNG_DLL_NOT_LOADED = 'Plugin DLL "%s" could not be loaded.';
467
  LNG_METHOD_NOT_FOUND = 'Method "%s" not found in plugin "%s". The DLL is probably not a valid plugin DLL.';
468
  LNG_INVALID_PLUGIN = 'The plugin "%s" is not a valid plugin for this program version.';
469
  LNG_METHOD_FAILURE = 'Error "%s" at method "%s" of plugin "%s".';
470
begin
70 daniel-mar 471
  result := false;
69 daniel-mar 472
  startTime := GetTickCount;
473
 
474
  dllHandle := LoadLibrary(PChar(dllFile));
475
  if dllHandle = 0 then
476
  begin
477
    Errors.Add(Format(LNG_DLL_NOT_LOADED, [dllFile]));
478
  end;
479
  try
480
    @fPluginInterfaceID := GetProcAddress(dllHandle, mnPluginInterfaceID);
481
    if not Assigned(fPluginInterfaceID) then
482
    begin
483
      Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginInterfaceID, dllFile]));
484
      Exit;
485
    end;
486
    pluginInterfaceID := fPluginInterfaceID();
487
    if not IsEqualGUID(pluginInterfaceID, GUID_USERDETECT2_IDPLUGIN_V1) then
488
    begin
489
      Errors.Add(Format(LNG_INVALID_PLUGIN, [dllFile]));
490
      Exit;
491
    end;
492
 
493
    @fIdentificationStringW := GetProcAddress(dllHandle, mnIdentificationStringW);
494
    if not Assigned(fIdentificationStringW) then
495
    begin
496
      Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnIdentificationStringW, dllFile]));
497
      Exit;
498
    end;
499
 
500
    @fPluginNameW := GetProcAddress(dllHandle, mnPluginNameW);
501
    if not Assigned(fPluginNameW) then
502
    begin
503
      Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginNameW, dllFile]));
504
      Exit;
505
    end;
506
 
507
    @fPluginVendorW := GetProcAddress(dllHandle, mnPluginVendorW);
508
    if not Assigned(fPluginVendorW) then
509
    begin
510
      Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginVendorW, dllFile]));
511
      Exit;
512
    end;
513
 
514
    @fPluginVersionW := GetProcAddress(dllHandle, mnPluginVersionW);
515
    if not Assigned(fPluginVersionW) then
516
    begin
517
      Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginVersionW, dllFile]));
518
      Exit;
519
    end;
520
 
521
    @fCheckLicense := GetProcAddress(dllHandle, mnCheckLicense);
522
    if not Assigned(fCheckLicense) then
523
    begin
524
      Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnCheckLicense, dllFile]));
525
      Exit;
526
    end;
527
 
528
    @fIdentificationMethodNameW := GetProcAddress(dllHandle, mnIdentificationMethodNameW);
529
    if not Assigned(fIdentificationMethodNameW) then
530
    begin
531
      Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnIdentificationMethodNameW, dllFile]));
532
      Exit;
533
    end;
534
 
70 daniel-mar 535
    @fDescribeOwnStatusCodeW := GetProcAddress(dllHandle, mnDescribeOwnStatusCodeW);
536
    if not Assigned(fDescribeOwnStatusCodeW) then
537
    begin
538
      Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnDescribeOwnStatusCodeW, dllFile]));
539
      Exit;
540
    end;
541
 
69 daniel-mar 542
    pl := TUD2Plugin.Create;
543
    pl.PluginDLL := dllFile;
544
 
545
    pluginIDfound := false;
546
    sPluginConfigFile := ChangeFileExt(dllFile, '.ini');
547
    if FileExists(sPluginConfigFile) then
548
    begin
549
      iniConfig := TIniFile.Create(sPluginConfigFile);
550
      try
551
        sOverrideGUID := iniConfig.ReadString('Compatibility', 'OverrideGUID', '');
552
        if sOverrideGUID <> '' then
553
        begin
554
          pl.PluginGUID := StringToGUID(sOverrideGUID);
555
          pluginIDfound := true;
556
        end;
557
      finally
558
        iniConfig.Free;
559
      end;
560
    end;
561
 
562
    if not pluginIDfound then
563
    begin
564
      @fPluginIdentifier := GetProcAddress(dllHandle, mnPluginIdentifier);
565
      if not Assigned(fPluginIdentifier) then
566
      begin
567
        Errors.Add(Format(LNG_METHOD_NOT_FOUND, [mnPluginIdentifier, dllFile]));
568
        Exit;
569
      end;
570
      pl.PluginGUID := fPluginIdentifier();
571
    end;
572
 
573
    statusCode := fCheckLicense(nil);
574
    if UD2_STATUS_Failed(statusCode) then
575
    begin
70 daniel-mar 576
      Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnCheckLicense, dllFile]));
69 daniel-mar 577
      Exit;
578
    end;
579
 
580
    statusCode := fPluginNameW(@buf, cchBufferSize, lngID);
581
         if UD2_STATUS_Successful(statusCode) then pl.PluginName := PWideChar(@buf)
582
    else if UD2_STATUS_NotAvail(statusCode)   then pl.PluginName := ''
583
    else
584
    begin
70 daniel-mar 585
      Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginNameW, dllFile]));
69 daniel-mar 586
      Exit;
587
    end;
588
 
589
    statusCode := fPluginVendorW(@buf, cchBufferSize, lngID);
590
         if UD2_STATUS_Successful(statusCode) then pl.PluginVendor := PWideChar(@buf)
591
    else if UD2_STATUS_NotAvail(statusCode)   then pl.PluginVendor := ''
592
    else
593
    begin
70 daniel-mar 594
      Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginVendorW, dllFile]));
69 daniel-mar 595
      Exit;
596
    end;
597
 
598
    statusCode := fPluginVersionW(@buf, cchBufferSize, lngID);
599
         if UD2_STATUS_Successful(statusCode) then pl.PluginVersion := PWideChar(@buf)
600
    else if UD2_STATUS_NotAvail(statusCode)   then pl.PluginVersion := ''
601
    else
602
    begin
70 daniel-mar 603
      Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnPluginVersionW, dllFile]));
69 daniel-mar 604
      Exit;
605
    end;
606
 
607
    statusCode := fIdentificationMethodNameW(@buf, cchBufferSize);
608
         if UD2_STATUS_Successful(statusCode) then pl.IdentificationMethodName := PWideChar(@buf)
609
    else if UD2_STATUS_NotAvail(statusCode)   then pl.IdentificationMethodName := ''
610
    else
611
    begin
70 daniel-mar 612
      Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnIdentificationMethodNameW, dllFile]));
69 daniel-mar 613
      Exit;
614
    end;
615
 
616
    statusCode := fIdentificationStringW(@buf, cchBufferSize);
70 daniel-mar 617
    pl.IdentificationProcedureStatusCode := statusCode;
618
    pl.IdentificationProcedureStatusCodeDescribed := _ErrorLookup(statusCode);
69 daniel-mar 619
    if UD2_STATUS_Successful(statusCode) then
620
    begin
621
      sIdentifier := PWideChar(@buf);
622
      if statusCode = UD2_STATUS_OK_MULTILINE then
623
      begin
70 daniel-mar 624
        // Multiple identifiers (e.g. multiple MAC addresses are delimited via UD2_MULTIPLE_ITEMS_DELIMITER)
69 daniel-mar 625
        SetLength(sIdentifiers, 0);
626
        sIdentifiers := SplitString(UD2_MULTIPLE_ITEMS_DELIMITER, sIdentifier);
627
        for i := Low(sIdentifiers) to High(sIdentifiers) do
628
        begin
629
          pl.AddIdentification(sIdentifiers[i]);
630
        end;
631
      end
632
      else
633
      begin
634
        pl.AddIdentification(sIdentifier);
635
      end;
636
    end
637
    else if not UD2_STATUS_NotAvail(statusCode) then
638
    begin
70 daniel-mar 639
      // Errors.Add(Format(LNG_METHOD_FAILURE, [_ErrorLookup(statusCode), mnIdentificationStringW, dllFile]));
640
      Errors.Add(Format(LNG_METHOD_FAILURE, [pl.IdentificationProcedureStatusCodeDescribed, mnIdentificationStringW, dllFile]));
69 daniel-mar 641
      Exit;
642
    end;
643
 
644
    endtime := GetTickCount;
645
    time := endtime - starttime;
646
    if endtime < starttime then time := High(Cardinal) - time;
647
    pl.time := time;
648
 
70 daniel-mar 649
    result := true;
69 daniel-mar 650
  finally
70 daniel-mar 651
    if not result and Assigned(pl) then FreeAndNil(pl);
69 daniel-mar 652
    FreeLibrary(dllHandle);
653
  end;
654
end;
655
 
68 daniel-mar 656
end.