delphi – always pass SEM_FAILCRITICALERRORS to SafeLoadLibrary
Posted by jpluimers on 2020/05/19
The below is based on [WayBack] delphi – Is there any way to catch the error if loading a dll cannot find a dependency? – Stack Overflow which I got via:
- [WayBack] Error regarding rtl240.bpl not found in stand alone version of GExperts Grep – twm’s blog
- [WayBack] Do not call SafeLoadLibrary(‘dllname.dll’) – twm’s blog
The problem is that the [WayBack] SysUtils.SafeLoadLibrary Function (present since at least Delphi 2007, and a wrapper around the [WayBack] LoadLibrary function (Windows)) does many good things – maybe even too many – so you need to take all of them into account:
function SafeLoadLibrary(const FileName: string; ErrorMode: UINT = SEM_NOOPENFILEERRORBOX): HMODULE;
SafeLoadLibrary
loads a Windows DLL or Linux shared object file, as specified byFilename
.SafeLoadLibrary
preserves the current FPU control word, preventing library initialization code from permanently overwriting precision and exception masks.- Note:
- On Windows,
SafeLoadLibrary
temporarily sets the system error mode toErrorMode
. The default,SEM_NOOPENFILEERRORBOX
, suppresses error dialogs. The previous error mode is restored beforeSafeLoadLibrary
exits. For a list of error modes, refer to [Wayback1/Wayback2] SetErrorMode in the Microsoft documentation. - Note: On Linux, the
Dummy
argument is ignored.
- On Windows,
Most important tips
Do not ever pass 0
(the number zero) as ErrorMode
; I’ve seen lots of applications just passing zero for parameters they are not sure about, but in this case it is the worst solution as it will show all errors as a popup.
Do not forget a parameter either: the default value SEM_NOOPENFILEERRORBOX
will only suppress a message box when it fails to find a file. But it will fail to enable SEM_FAILCRITICALERRORS
which is what you really want.
Loading DLLs from resources
LoadLibrary
and SafeLoadLibrary
load the DLL from a file. But what if you want to load it from a resource?
Then this post from Thomas Mueller applies: he adopted the SafeLoadLibrary logic to load from a resource:
- [WayBack] If your floating point calculations differ after a trivial change – twm’s blog
- some additional comments at [WayBack] Today I had a curious bug: After changing the way GPS coordinates were read from a file (not calculated!) all of a sudden lots of unrelated floating poi… – Thomas Mueller (dummzeuch) – Google+
Other thoughts to keep in mind
The way Delphi sets the FPU control word is not thread safe: QualityCentral Report # 106943: Set8087CW/SetMXCSR are not thread-safe (you could work around in your implementation by using thread safe versions like mentioned in [WayBack] FastMM / Discussion / Open Discussion:Call to GetStackTrace changes 8087CW).
Calling SetErrorMode
sets a global application wide setting (by default including all threads) of error code, so it is better to either:
- decide for your whole application up front which error mode to use, save it and use the same value everywhere:
Because the error mode is set for the entire process, you must ensure that multi-threaded applications do not set different error-mode flags. Doing so can lead to inconsistent error handling.
- decide between the global or local error mode methods:
Second, SEM_FAILCRITICALERRORS
prevents an error to pop up when dependencies of the loaded file are not available. You might want to combine (bitwise or
) it with other values like SEM_NOGPFAULTERRORBOX
.
ErrorMode values
There are many more modes you can pass to the [WayBack] SetErrorMode function (Windows):
-
Value Meaning - 0
Use the system default, which is to display all error dialog boxes. - SEM_FAILCRITICALERRORS
- 0x0001
The system does not display the critical-error-handler message box. Instead, the system sends the error to the calling process. Best practice is that all applications call the process-wide SetErrorMode function with a parameter of SEM_FAILCRITICALERRORS at startup. This is to prevent error mode dialogs from hanging the application.
- SEM_NOALIGNMENTFAULTEXCEPT
- 0x0004
The system automatically fixes memory alignment faults and makes them invisible to the application. It does this for the calling process and any descendant processes. This feature is only supported by certain processor architectures. For more information, see the Remarks section. After this value is set for a process, subsequent attempts to clear the value are ignored.
- SEM_NOGPFAULTERRORBOX
- 0x0002
The system does not display the Windows Error Reporting dialog. - SEM_NOOPENFILEERRORBOX
- 0x8000
The OpenFile function does not display a message box when it fails to find a file. Instead, the error is returned to the caller. This error mode overrides the OF_PROMPT flag.
–jeroen
all via:
- [WayBack] Various people have reported an error message regarding rtl240.bpl not being found when calling the stand alone version of GExperts Grep. I could never … – Thomas Mueller (dummzeuch) – Google+
- [WayBack] Error regarding rtl240.bpl not found in stand alone version of GExperts Grep – twm’s blog
- [WayBack] delphi – Is there any way to catch the error if loading a dll cannot find a dependency? – Stack Overflow
- [WayBack] Do not call SafeLoadLibrary(‘dllname.dll’) – twm’s blog
Related:
- Delphi – Direct3D and the wrong FPU state: Now() function returns a wrong value (via: StackOverflow) « The Wiert Corner – irregular stream of stuff
- Delphi – Michael Justin had strange floating point results when his 8087 FPU Control Word got hosed « The Wiert Corner – irregular stream of stuff
- Delphi history – on the FINITEFLOAT compiler option that has no one-character shortcut « The Wiert Corner – irregular stream of stuff
Leave a Reply