-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
DynLibUtils.pas
2795 lines (2301 loc) · 102 KB
/
DynLibUtils.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{-------------------------------------------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
-------------------------------------------------------------------------------}
{===============================================================================
Dynamic Library Utilities
Main aim of this small library is to encapsulate dynamic library loading
and symbol resolving (ie. obtaining addresses of functions and variables)
on different systems.
There are also contexts which offer more advanced options, but they are
currently untested - use them with caution.
Version 1.4 (2024-10-14)
Last change 2024-10-14
©2020-2024 František Milt
Contacts:
František Milt: [email protected]
Support:
If you find this code useful, please consider supporting its author(s) by
making a small donation using the following link(s):
https://www.paypal.me/FMilt
Changelog:
For detailed changelog and history please refer to this git repository:
github.com/TheLazyTomcat/Lib.DynLibUtils
Dependencies:
* AuxExceptions - github.com/TheLazyTomcat/Lib.AuxExceptions
AuxTypes - github.com/TheLazyTomcat/Lib.AuxTypes
InterlockedOps - github.com/TheLazyTomcat/Lib.InterlockedOps
* SimpleCPUID - github.com/TheLazyTomcat/Lib.SimpleCPUID
StrRect - github.com/TheLazyTomcat/Lib.StrRect
* WindowsVersion - github.com/TheLazyTomcat/Lib.WindowsVersion
Library AuxExceptions is required only when rebasing local exception classes
(see symbol DynLibUtils_UseAuxExceptions for details).
Library SimpleCPUID is required only when compiling for x86(-64) CPU.
Library WindowsVersion is required only when compiling for Windows OS.
Libraries AuxExceptions and SimpleCPUID might also be required as an indirect
dependencies.
Indirect dependencies:
UInt64Utils - github.com/TheLazyTomcat/Lib.UInt64Utils
WinFileInfo - github.com/TheLazyTomcat/Lib.WinFileInfo
===============================================================================}
unit DynLibUtils;
{
DynLibUtils_PurePascal
If you want to compile this unit without ASM, don't want to or cannot define
PurePascal for the entire project and at the same time you don't want to or
cannot make changes to this unit, define this symbol for the entire project
and this unit will be compiled in PurePascal mode.
Note that, in fact, this unit cannot be compiled without asm when compiling
for x86(-64) processor.
}
{$IFDEF DynLibUtils_PurePascal}
{$DEFINE PurePascal}
{$ENDIF}
{
DynLibUtils_UseAuxExceptions
If you want library-specific exceptions to be based on more advanced classes
provided by AuxExceptions library instead of basic Exception class, and don't
want to or cannot change code in this unit, you can define global symbol
DynLibUtils_UseAuxExceptions to achieve this.
}
{$IF Defined(DynLibUtils_UseAuxExceptions)}
{$DEFINE UseAuxExceptions}
{$IFEND}
//------------------------------------------------------------------------------
{$IF defined(CPU64) or defined(CPU64BITS)}
{$DEFINE CPU64bit}
{$ELSEIF defined(CPU16)}
{$MESSAGE FATAL '16bit CPU not supported'}
{$ELSE}
{$DEFINE CPU32bit}
{$IFEND}
{$IF Defined(CPU386) or Defined(CPUX86_64) or Defined(CPUX64)}
{$DEFINE CPU_x86x}
{$IFEND}
{$IF Defined(WINDOWS) or Defined(MSWINDOWS)}
{$DEFINE Windows}
{$ELSEIF Defined(LINUX) and Defined(FPC)}
{$DEFINE Linux}
{$ELSE}
{$MESSAGE FATAL 'Unsupported operating system.'}
{$IFEND}
{$IFDEF FPC}
{$MODE ObjFPC}
{$MODESWITCH CLASSICPROCVARS+}
{$IFDEF CPU_x86x}
{$ASMMODE Intel}
{$ENDIF}
{$INLINE ON}
{$DEFINE CanInline}
{$DEFINE FPC_DisableWarns}
{$MACRO ON}
{$ELSE}
{$IF CompilerVersion >= 17} // Delphi 2005+
{$DEFINE CanInline}
{$ELSE}
{$UNDEF CanInline}
{$IFEND}
{$ENDIF}
{$H+}
{$IF Defined(CPU_x86x) and Defined(PurePascal) and not Defined(CompTest)}
{$MESSAGE WARN 'This unit cannot be compiled without ASM.'}
{$IFEND}
interface
uses
{$IFDEF Windows}Windows,{$ENDIF} SysUtils, Classes,
AuxTypes{$IFDEF UseAuxExceptions}, AuxExceptions{$ENDIF};
{===============================================================================
Library-specific exceptions
===============================================================================}
type
EDLUException = class({$IFDEF UseAuxExceptions}EAEGeneralException{$ELSE}Exception{$ENDIF});
EDLULibraryOpenError = class(EDLUException);
EDLULibraryCloseError = class(EDLUException);
EDLUInvalidParameter = class(EDLUException);
EDLUSymbolError = class(EDLUException);
{$IFDEF Windows}
{===============================================================================
Process error mode management - declaration
===============================================================================}
Function GetThreadErrorMode: DWORD;
Function SetThreadErrorMode(dwNewMode: DWORD; lpOldMode: LPDWORD): BOOL;
{$ENDIF}
{===============================================================================
Symbol resolving auxiliary - declaration
===============================================================================}
type
// TDLUSymbol is used in macro functions for symbol resolving
TDLUSymbol = record
Name: String; // name of the symbol
AddressVar: PPointer; // pointer to a variable to which the address shall be stored
end;
PDLUSymbol = ^TDLUSymbol;
// inline contructors for TDLUSymbol record
Function Symbol(const Name: String; AddressVar: PPointer): TDLUSymbol; overload; {$IFDEF CanInline}inline;{$ENDIF}
Function Symbol(AddressVar: PPointer; const Name: String): TDLUSymbol; overload; {$IFDEF CanInline}inline;{$ENDIF}
{===============================================================================
Utility functions - declaration
===============================================================================}
{
LibraryIsPresent
Tries to load the requested library. If it succeeds, it returns true,
otherwise it will return false.
Critical error dialog is suppressed.
}
Function LibraryIsPresent(const LibFileName: String): Boolean;
{
SymbolIsPresent
Returns true when requested symbol can be obtained from given library, false
otherwise.
If will first load the library, then it will try to normally resolve the
symbol and in the end will unload the library.
If the library cannot be loaded, it will raise an EDLULibraryOpenError
exception.
Critical error dialog is suppressed.
}
Function SymbolIsPresent(const LibFileName, SymbolName: String): Boolean;
{
LibrarySymbolIsPresent
Returns true when the requested library can be loaded and requested symbol
can be obtained from it, false otherwise. No exceptions are raised.
Critical error dialog is suppressed.
}
Function LibrarySymbolIsPresent(const LibFileName, SymbolName: String): Boolean;
{===============================================================================
--------------------------------------------------------------------------------
Handle functions
--------------------------------------------------------------------------------
===============================================================================}
{
Functions operating on library handles are supposed to be used only locally
(no global variables and such) or when the handles are strictly managed.
If you want to operate on libraries globally (ie. using global variables)
or from multiple threads, use contexts.
Given the implementation, a variable of type TDLULibraryHandle must be
assigned only once, because each call to CloseLibrary on it will invalidate
that variable.
}
{===============================================================================
Handle functions - declaration
===============================================================================}
type
TDLULibraryHandle = {$IFDEF Windows}THandle{$ELSE}Pointer{$ENDIF};
PDLULibraryHandle = ^TDLULibraryHandle;
const
DefaultLibraryHandle = TDLULibraryHandle({$IFDEF Windows}0{$ELSE}nil{$ENDIF});
type
{
TDLUOption
Individual values of this enumeration are used to activate or deactivate
specific options available in calls provided by this library.
Most of implemented functions support only a subset of all options - refer
to description of each function to see what options are observed.
optDeepCheck
Normally, when a library handle is checked for validity, it is only probed
whether is is assigned - ie. is not null or nil.
When this option is added, the checking continues by trying to obtain some
(inplementation-specific) information about the library using the handle.
If this succeeds, then the handle is assumed to be valid. In case of
failure it is assumed to be invalid.
optNoCriticalError
In Windows OS, when a library cannot be loaded for whatever reason, the
called WinAPI function will initiate critical system error, which will
display an error dialog (a window).
This might be very obtrusive (eg. when probing DLL existence) - so if this
behavior is undesirable, include this option and this error dialog will be
suppressed.
This option has effect only in Windows OS, it is ignored elsewhere.
WARNING - suppressing error dialog is inherently thread unsafe in systems
older than Windows 7.
optExceptionOnFailure
This option is somewhat universal, because it can be observed by several
groups of functions.
Functions opening/loading libraries (eg. OpenLibrary)
These usually indicate success or failure using boolean result. When
this option is activated, then an EDLULibraryOpenError exception is
raised when the loading fails for any reason (success is still
indicated by returning True).
Functions closing/unloading libraries (eg. CloseLibrary)
These functions normally do not check for errors when calling the
system functions doing the cleanup, but when this option is activated,
the check is performed and an EDLULibraryCloseError exception is raised
on failure.
Functions resolving symbols (eg. GetSymbolAddr or ResolveSymbol)
When resolving symbols, the failure is normally indicated by returning
a nil pointer. With this option active, the EDLUSymbolError exception
is raised whenever the symbol cannot be resolved.
NOTE - there are situations where nil pointer is considered to be a
valid return, so some functions might return nil and not raise
an exception even with this option.
optResolveNow
When activated, loading of a library also resolves all undefined symbol
before returning (RTLD_NOW is put into flags), as apposed to lazy binding
when this option is not active (flags contain RTLD_LAZY).
This has effect only in Linux OS, it is ignored in Windows. For more
information please refer to Linux manual (dlopen(3)).
optSafeLoad
Activate this option if you want to preserve some selected system settings
across the call when loading or unloading a library.
In current implementation, it preserves process/thread error mode on
Windows OS and X87 control word (FPU settings) and MXCSR register (SSE and
AVX settings) on x86(-64) processors.
It is here for situations where the loaded library is changing those
settings but this behavior is undesirable.
optBreakOnUnresolved
This option is observed only by functions resolving multiple symbols. When
active, it forces interruption of array/list traversal when currently
processed symbol cannot be resolved.
NOTE - option optExceptionOnFailure takes precedence over this one. If
both are active and symbol that cannot be resolved is encountered,
then an exception is raised as prescribed by optExceptionOnFailure.
optNoSerialize
This option affects only functions operating on contexts - when active,
the call does not lock the context it is operating on (is not serialized).
It can be used to improve performance in cases where serialization of
every single call is not necessary.
WARNING - this option is observed only when added to call parameter
Options, its presence in context-stored options is ignored.
This is due to a fact that context needs to be locked before
the stored options can be accessed and probed for this option,
and that locking directly contradicts this option being used.
WARNING - take great care where and when you use this option, as using
it in an inappropriate situation will inadvertently lead to
corruption of the affected context.
Generally, you should never use this option on sole calls,
use it only if the context is currently thread locked, as
the locking and unlocking calls do way more than just that.
optAlwaysLoad
Under normal circumstances, context function OpenLibrary loads the library
(that is, calls system function to do so) only when first called on
particular context variable - that variable is initialized in this call
and the library is loaded. On subsequent calls it only increments internal
reference count.
But when this option is active, then this function loads the library even
if the context is already intialized and library was already loaded.
This option works similarly for CloseLibrary - this function decrements
the internal reference count and only unloads the library if the count
reaches zero. With this option active it always cloases the library
(whether it is unloaded is decided by the OS).
Each opening call with this option active must be paired by a closing
class with it.
Note that operating system keeps its own reference count for each loaded
module/object, so this option might seem to be somewhat superfluous. But
it is intended for situation where repeated loading or closing of one
library pose some problem, whatever it migh be.
optSymbolListResolve
If this option is active during symbol resolving using context, then the
symbol is first searched for in context's list of resolved symbols.
If found there, then address stored in this list is returned. When not
found, then the symbol is resolved as usual (using system call and stored
library handle).
optSymbolListStore
When resolving symbols using contexts with this option enabled, every
successfully resolved symbol is stored along with its address in the list
of resolved symbols within the context - as long as it was not resolved
using the list (see optSymbolListResolve). If this option is not active,
then nothing is written to this list.
If the resolved symbol already is in the list, its address is updated
on every new successful resolving.
optContextOptions
Affects only functions working with contexts.
Each context stores its own options set, but under normal circumstances all
functions working with contexts will use options given in the call argument
Options, even if nothing is explicitly assigned there (a default empty set
is used).
When this option is included in Options parameter, then the called function
will use context-stored options to alter its behaviour and will ignore
other options given in the parameter. If this is active in contex options,
then all calls working on that context will use contex options, irrespective
of whether optContextOptions is given in Options argument or not.
}
TDLUOption = (optDeepCheck,optNoCriticalError,optExceptionOnFailure,
optResolveNow,optSafeLoad,optBreakOnUnresolved,optNoSerialize,
optAlwaysLoad,optSymbolListResolve,optSymbolListStore,
optContextOptions);
TDLUOptions = set of TDLUOption;
{
TDLUSymReslResult
TDLUSymReslResults
These types are used when resolving multiple symbols to indicate which
symbols were passed to resolving (field Processed) and which were succesfully
resolved (field Resolved).
It can be used eg. in situation where option optBreakOnUnresolved is not
activated and some symbols could not be resolved - to find which ones.
}
TDLUSymReslResult = record
Processed: Boolean;
Resolved: Boolean;
end;
TDLUSymReslResults = array of TDLUSymReslResult;
{-------------------------------------------------------------------------------
Handle functions - library functions
-------------------------------------------------------------------------------}
{
CheckLibrary
Returns true when passed library handle is valid, false otherwise.
Observed options:
optDeepCheck
}
Function CheckLibrary(LibraryHandle: TDLULibraryHandle; Options: TDLUOptions = []): Boolean; overload;
{
OpenLibrary
Loads the requested library and returns a handle to it. It will return null
or nil (depending on OS) if it cannot be loaded.
This handle must be closed using function CloseLibrary when you are done
with it.
Observed options:
optDeepCheck, optNoCriticalError, optExceptionOnFailure, optResolveNow,
optSafeLoad
}
Function OpenLibrary(const LibFileName: String; Options: TDLUOptions = []): TDLULibraryHandle; overload;
{
OpenLibrary
Loads the requested library and returns handle to it in output parameter
LibraryHandle. This parameter is set to null or nil (depending on OS) if
the library cannot be loaded. Returns true when the loading succeeds, false
otherwise.
NOTE - CheckLibrary is called internally to check whether the library was
loaded successfully or not.
The returned library handle must be closed using function CloseLibrary when
you are done using it.
If an exception is raised, then value of LibraryHandle is undefined.
Observed options:
optDeepCheck, optNoCriticalError, optExceptionOnFailure, optResolveNow,
optSafeLoad
}
Function OpenLibrary(const LibFileName: String; out LibraryHandle: TDLULibraryHandle; Options: TDLUOptions = []): Boolean; overload;
{
CloseLibrary
Closes and potentially unloads the library (unloading is managed by the OS).
It checks the handle (calls CheckLibrary) before processing. If it is not
deemed to be valid, it will exit without doing anything (no exception).
Note that it will always invalide the library handle, irrespective of whether
the OS unloads the library or not.
Observed options:
optDeepCheck, optSafeLoad, optExceptionOnFailure
}
procedure CloseLibrary(var LibraryHandle: TDLULibraryHandle; Options: TDLUOptions = []); overload;
{-------------------------------------------------------------------------------
Handle functions - symbols addresses
-------------------------------------------------------------------------------}
{
GetSymbolAddr
Returns pointer to requested symbol. If it cannot be resolved, it returns nil.
If the library handle is not valid, it will raise an EDLUInvalidParameter
exception (irrespective of whether optExceptionOnFailure is included in
options or not).
Observed options:
optDeepCheck, optExceptionOnFailure
}
Function GetSymbolAddr(LibraryHandle: TDLULibraryHandle; const SymbolName: String; Options: TDLUOptions = []): Pointer; overload;
{
GetSymbolAddr
Stores address of requested symbol to Address output parameter.
Returns true when the symbol was properly resolved, false otherwise (in which
case the value of Address is undefined).
Always raises an EDLUInvalidParameter exception if the library handle is not
valid.
This function is intended for situations where one wants to check validity
of returned address even if it can be nil, without raising an exception.
Observed options:
optDeepCheck, optExceptionOnFailure
}
Function GetSymbolAddr(LibraryHandle: TDLULibraryHandle; const SymbolName: String; out Address: Pointer; Options: TDLUOptions = []): Boolean; overload;
{-------------------------------------------------------------------------------
Handle functions - symbols resolving
-------------------------------------------------------------------------------}
{
ResolveSymbol
Resolves symbol whose name is given in Name field of parameter Symbol and
stores its address to a variable pointed to by the field AddressVar in the
same parameter. When it succeeds then True is returned, on failure False is
returned.
Note that variable for symbol address might be assigned even on failure,
in which case its content is undefined.
Always raises an EDLUInvalidParameter exception if the library handle is not
valid.
Observed options:
optDeepCheck, optExceptionOnFailure
}
Function ResolveSymbol(LibraryHandle: TDLULibraryHandle; Symbol: TDLUSymbol; Options: TDLUOptions = []): Boolean; overload;
{
ResolveSymbols
Traverses given array of TDLUSymbol records (parameter Symbols) and tries to
resolve all symbols within (see description of function ResolveSymbol for
details as this function is internally called). Note that if one symbol is
included multiple-times, it is resolved separately for each iteration (there
is no duplicity protection).
Result is set to number of successfully resolved symbols. If this number is
equal to length of given array, then all symbols have been resolved without
errors.
Output parameter Results (in overload accepting this parameter) can be probed
to see which symbols were successfully resolved and which not in case the
returned count indicates not all were.
Always raises an EDLUInvalidParameter exception if the library handle is not
valid.
NOTE - validity of provided library handle is checked even if no symbols
(an empty array) is given.
Observed options:
optDeepCheck, optExceptionOnFailure, optBreakOnUnresolved
}
Function ResolveSymbols(LibraryHandle: TDLULibraryHandle; const Symbols: array of TDLUSymbol; out Results: TDLUSymReslResults; Options: TDLUOptions = []): Integer; overload;
Function ResolveSymbols(LibraryHandle: TDLULibraryHandle; const Symbols: array of TDLUSymbol; Options: TDLUOptions = []): Integer; overload;
{
ResolveSymbolList
This function works the same as ResolveSymbols (see there for more info),
but names of individual symbols are taken from items of passed string list
and resulting addresses are stored at respective places in the list's Objects
property (the pointers are casted to TObject).
Parameter SymbolList is not declared as more general TStrings because that
class does not fully implement Objects property, which is required here.
Always raises an EDLUInvalidParameter exception if the library handle is not
valid.
NOTE - validity of provided library handle is checked even if no symbols
(an empty list) is given.
Observed options:
optDeepCheck, optExceptionOnFailure, optBreakOnUnresolved
}
Function ResolveSymbolList(LibraryHandle: TDLULibraryHandle; SymbolList: TStringList; out Results: TDLUSymReslResults; Options: TDLUOptions = []): Integer; overload;
Function ResolveSymbolList(LibraryHandle: TDLULibraryHandle; SymbolList: TStringList; Options: TDLUOptions = []): Integer; overload;
{
ResolveSymbolNames
Works the same as ResolveSymbols (see there for more info), but names of
individual symbols are taken from items in Names array and the resulting
addresses are stored to variables pointed to by respective items in
AddressPtrs array (eg. address for name in Names[3] is stored to variable
pointed to by AddressVars[3]).
Length of both Names and AddressVars arrays must be the same, otherwise an
EDLUInvalidParameter exception is raised (irrespective of whether option
optExceptionOnFailure is active or not).
Always raises an EDLUInvalidParameter exception if the library handle is not
valid.
NOTE - validity of provided library handle is checked even if no symbols
(an empty arrays) is given.
Observed options:
optDeepCheck, optExceptionOnFailure, optBreakOnUnresolved
}
Function ResolveSymbolNames(LibraryHandle: TDLULibraryHandle; const Names: array of String;
const AddressVars: array of PPointer; out Results: TDLUSymReslResults; Options: TDLUOptions = []): Integer; overload;
Function ResolveSymbolNames(LibraryHandle: TDLULibraryHandle; const Names: array of String;
const AddressVars: array of PPointer; Options: TDLUOptions = []): Integer; overload;
{-------------------------------------------------------------------------------
Handle functions - macro functions
-------------------------------------------------------------------------------}
{
OpenLibraryAndResolveSymbol(s/List/Names)
All these functions are just simple macros calling OpenLibrary (overload
directly returning handle) and then appropriate ResolveSymbol(s/List/Names).
Refer to description of those called functions for their behavior (observed
options, raised exceptions, meaning of parameters, return values, ...).
Returns a return value of particular ResolveSymbol* used in the implementation
of given function.
If an exception is raised, then content of the output parameter LibraryHandle
is undefined (if the exception is raised after the library was successfully
opened, it is automatically closed).
NOTE - given options are in effect for both OpenLibrary and ResolveSymbol*.
This must be considered especially for option optExceptionOnFailure.
Observed options:
optDeepCheck, optNoCriticalError, optExceptionOnFailure, optResolveNow,
optSafeLoad, optBreakOnUnresolved
}
Function OpenLibraryAndResolveSymbols(const LibFileName: String; out LibraryHandle: TDLULibraryHandle;
Symbols: array of TDLUSymbol; out Results: TDLUSymReslResults; Options: TDLUOptions = []): Integer; overload;
Function OpenLibraryAndResolveSymbols(const LibFileName: String; out LibraryHandle: TDLULibraryHandle;
Symbols: array of TDLUSymbol; Options: TDLUOptions = []): Integer; overload;
Function OpenLibraryAndResolveSymbolList(const LibFileName: String; out LibraryHandle: TDLULibraryHandle;
SymbolList: TStringList; out Results: TDLUSymReslResults; Options: TDLUOptions = []): Integer; overload;
Function OpenLibraryAndResolveSymbolList(const LibFileName: String; out LibraryHandle: TDLULibraryHandle;
SymbolList: TStringList; Options: TDLUOptions = []): Integer; overload;
Function OpenLibraryAndResolveSymbolNames(const LibFileName: String; out LibraryHandle: TDLULibraryHandle;
const Names: array of String; const AddressVars: array of PPointer; out Results: TDLUSymReslResults; Options: TDLUOptions = []): Integer; overload;
Function OpenLibraryAndResolveSymbolNames(const LibFileName: String; out LibraryHandle: TDLULibraryHandle;
const Names: array of String; const AddressVars: array of PPointer; Options: TDLUOptions = []): Integer; overload;
{===============================================================================
--------------------------------------------------------------------------------
Context functions
--------------------------------------------------------------------------------
===============================================================================}
{
Contexts provide more robust way of loading libraries and storing their
handles for symbol resolving and unloading, and are a preffered way if you
want to operate on libraries using global variables or in a multi-thread
environment, as access to each context is serialized. But note that for
simple cases it is still better to use library handles as they have much
lower overhead.
Each context stores and provides not only the handle obtained when loading
a library, but also more information about that library along with some
statistics, though this is currently implemented only in a limited form.
The most important feature of contexts is, that the library to which a
context is bound is loaded (ie. system function loading it is called) only
once, in the first loading call. Also, the system freeing is done only once.
This is achieved by maintaining an internal reference count. But note that
this all holds true only per context, not globally (the same library can be
loaded using a different context), and also can be disabled using options.
Because the loading indicates whether the library was already loaded or not,
this can be also used for optimizations in symbol resolving (ie. resolving is
performed only on the first load and is omitted on subsequent load calls).
For more information, refer to description of types and functions operating
on contexts.
}
{===============================================================================
Context functions - declaration
===============================================================================}
type
{
TDLULibraryContextData
This structure is used to store and return information and statistics about
specific context.
Some fields might need clarification, namely:
OpenCount
Stores how many times was this context used to open its library. It gets
decremented on each closing.
OpenFileName
Stores exact string that was used to load the library - ie. the string
used in a call that initialized this context.
FullFileName
This string is obtained from OS using the opened library handle. It is
here to provide full library path when only file name or relative path
was used to load the library.
ResolvedSymbols
This stores a list of already resolved symbols with their addresses.
}
TDLULibraryContextData = record
Handle: TDLULibraryHandle;
OpenCount: Integer;
OpenFileName: String;
FullFileName: String;
Options: TDLUOptions;
ResolvedSymbols: array of record
Name: String;
Address: Pointer;
end;
end;
const
{
DLUContextSize
DLUContextWords
These two constants are intended only for internal use, please ignore them
as they might be changed or even removed in the future.
}
DLUContextSize = (3 * SizeOf(Integer)) + SizeOf(Boolean) + SizeOf(TObject) + SizeOf(TDLULibraryContextData);
DLUContextWords = (DLUContextSize + {$IFDEF CPU64bit}7) shr 3{$ELSE}3) shr 2{$ENDIF};
type
{
TDLULibraryContext
Semi-opaque public type used to store the actual internal context.
Always make sure to initialize the context variable, either by assigning
DefaultLibraryContext constant to it or by zeroing the memory. But note that
in (object) pascal, global and thread variables are automatically zeroed by
the compiller, so this applies mainly to local or reused variables.
}
TDLULibraryContext = array[0..Pred(DLUContextWords)] of NativeInt;
PDLULibraryContext = ^TDLULibraryContext;
const
DefaultLibraryContext: TDLULibraryContext =
(0,0,0,0,0,0,0,0,0{$IFNDEF CPU64bit},0,0{$ENDIF});
{-------------------------------------------------------------------------------
Context functions - utility functions
-------------------------------------------------------------------------------}
{
ContextLock
Locks the passed context so that only the current thread can access it.
If this function is called while the lock is held by other thread, the call
will block until the holder realeases its lock.
Nested locks are allowed, but each lock operation must be paired with an
unlock operation (a call to ContextUnlock).
This direct access to internal lock is provided to allow for more complex
operations on the context to be performed atomically - everything between
ContextLock-ContextUnlock calls will be executed in a thread-safe manner.
}
procedure ContextLock(var Context: TDLULibraryContext); overload;
{
ContextUnlock
Unlocks the passed context.
}
procedure ContextUnlock(var Context: TDLULibraryContext); overload;
//------------------------------------------------------------------------------
{
ContextGetData
Returns information and statistics of the passed context.
Raises an EDLUInvalidParameter exception if the context is not valid.
WARNING - if the context is accessed from multiple threads, then returned
data might not be accurate by the time the function returns,
unless it is called inside a locked block.
Observed options:
optDeepCheck, optNoSerialize, optContextOptions
}
Function ContextGetData(var Context: TDLULibraryContext; Options: TDLUOptions = []): TDLULibraryContextData;
{
ContextGetOptions
Returns context-stored options.
Each context stores its own set of options that can be used to alter
behaviour of calls performed on that context - see description of type
TDLUOption, enum value optContextOptions.
Raises an EDLUInvalidParameter exception if the context is not valid.
WARNING - if the context is accessed from multiple threads, then returned
value might not be accurate by the time the function returns,
unless it is called inside a locked block.
Observed options:
optDeepCheck, optNoSerialize, optContextOptions
}
Function ContextGetOptions(var Context: TDLULibraryContext; Options: TDLUOptions = []): TDLUOptions;
{
ContextSetOptions
Sets context-stored options to NewOptions and returns their previous value.
Raises an EDLUInvalidParameter exception if the context is not valid.
WARNING - if the context is accessed from multiple threads, then returned
value might not be accurate by the time the function returns,
unless it is called inside a locked block.
Observed options:
optDeepCheck, optNoSerialize, optContextOptions
}
Function ContextSetOptions(var Context: TDLULibraryContext; NewOptions: TDLUOptions; Options: TDLUOptions = []): TDLUOptions;
{
ContextSetOptions
Returns state of selected Option within context-stored options. If the option
is active, then True is returned, false otherwise.
Raises an EDLUInvalidParameter exception if the context is not valid.
WARNING - if the context is accessed from multiple threads, then returned
value might not be accurate by the time the function returns,
unless it is called inside a locked block.
Observed options:
optDeepCheck, optNoSerialize, optContextOptions
}
Function ContextGetOption(var Context: TDLULibraryContext; Option: TDLUOption; Options: TDLUOptions = []): Boolean;
{
ContextSetOptions
Sets selected Option in context-stored options of given context to a value
selected in NewState. When NewState is set to true, then the selected option
is enabled, when set to false then it is disabled. Returns previous state of
the selected option.
Raises an EDLUInvalidParameter exception if the context is not valid.
WARNING - if the context is accessed from multiple threads, then returned
value might not be accurate by the time the function returns,
unless it is called inside a locked block.
Observed options:
optDeepCheck, optNoSerialize, optContextOptions
}
Function ContextSetOption(var Context: TDLULibraryContext; Option: TDLUOption; NewState: Boolean; Options: TDLUOptions = []): Boolean;
{
ContextSetOptions
Enables selected Option in context-stored options of given context, returning
previous value of those options.
Raises an EDLUInvalidParameter exception if the context is not valid.
WARNING - if the context is accessed from multiple threads, then returned
value might not be accurate by the time the function returns,
unless it is called inside a locked block.
Observed options:
optDeepCheck, optNoSerialize, optContextOptions
}
Function ContextIncludeOption(var Context: TDLULibraryContext; Option: TDLUOption; Options: TDLUOptions = []): TDLUOptions;
{
ContextSetOptions
Disables selected Option in context-stored options of given context, returning
previous value of those options.
Raises an EDLUInvalidParameter exception if the context is not valid.
WARNING - if the context is accessed from multiple threads, then returned
value might not be accurate by the time the function returns,
unless it is called inside a locked block.
Observed options:
optDeepCheck, optNoSerialize, optContextOptions
}
Function ContextExcludeOption(var Context: TDLULibraryContext; Option: TDLUOption; Options: TDLUOptions = []): TDLUOptions;
{-------------------------------------------------------------------------------
Context functions - library functions
-------------------------------------------------------------------------------}
{
CheckLibrary
Returns true when the passed context is valid, false otherwise.
Context is considered valid when a library was previously successfully opened
using it, ie. it contains a valid handle to a loaded library.
Observed options:
optDeepCheck, optNoSerialize, optContextOptions
}
Function CheckLibrary(var Context: TDLULibraryContext; Options: TDLUOptions = []): Boolean; overload;
{
OpenLibrary
If the context is not initialized, then it initializes the provided context
variable (context-stored options are initialized to an empty set), loads
the requested library and returns true.
If the context is already initialized (that is, it was previously used to
successfully load a library), then it will return false and further behavior
of this functions depends on whether option optAlwaysLoad is active or not...
optAlwaysLoad is active
The function loads the library (calls system function) again and also
increments internal reference count. Stored handle is not updated as
the system function should return the same handle for the same opened
object (both in Windows and Linux) - this is checked and if the new
handle do not match the stored one, then an EDLULibraryOpenError
exception s raised.
The string given in LibFileName is ignored, instead a string stored in
the context's field FullFileName is used.
optAlwaysLoad is not active
Function does NOT load the library again, only increments context's
internal reference count (field OpenCount). LibFileName is ignored.
WARNING - in both cases, no check is performed whether the currently
requested file is the same as was opened in the original loading