Subversion Repositories userdetect2

Rev

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