Subversion Repositories userdetect2

Rev

Rev 92 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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