Subversion Repositories userdetect2

Rev

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