The following code is from the Windows 10 Anniversary Update SDK. I need the constant handles in order to use the API in Delphi because as of today, these headers are not included in Delphi.
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
When I use GetThreadDpiAwarenessContext in various DPI scenarios, I have learned what the values as NativeUInts are:
DPI_AWARENESS_CONTEXT_UNAWARE = 16;
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = 17;
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = 18;
But I would like to be 100% certain that these values are future-proof. They do work in SetThreadDpiAwarenessContext calls and have the desired effect, but I am unclear on how these values are arrived at. I could not duplicate a header construct in Delphi that produced those results, aside for the explicit integer declaration.
For use in SetThreadDpiAwarenessContext you should declare it as
type
DPI_AWARENESS_CONTEXT = type THandle;
const
DPI_AWARENESS_CONTEXT_UNAWARE = DPI_AWARENESS_CONTEXT(-1);
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = DPI_AWARENESS_CONTEXT(-2);
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE= DPI_AWARENESS_CONTEXT(-3);
but when you get response from GetThreadDpiAwarenessContext you need to use GetAwarenessFromDpiAwarenessContext on received value and compare it with DPI_AWARENESS enum.
You cannot directly compare DPI_AWARENESS_CONTEXT
since it contains multiple pieces of information and Microsoft may change it in the future.
Delphi does not use C/C++ include files at all, so it doesn't matter if the Windows SDK is shipped with the IDE or not, it won't be used in Delphi projects. Now, if you are worried about Delphi not providing Pascal translations of the C header files, that is another story.
DECLARE_HANDLE()
is a C preprocessor macro that declares a new data type alias based on the value of the input parameter and whether or not the preprocessor STRICT
conditional is defined:
#ifdef STRICT
typedef void *HANDLE;
#if 0 && (_MSC_VER > 1000)
#define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
#else
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
#endif
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
STRICT
provides more type-safety to C/C++ code. Many Win32 handle types are opaque types in user code. Declaring them using DECLARE_HANDLE()
allows the compiler to treat them as distinct data types when STRICT
is defined, thus prevents different handle types from being mixed together erroneously (ie, passing an HBITMAP
where an HWND
is expected, etc). A lot of developers made that kind of mistake before STRICT
was introduced, since all handle types were effectively void*
, preventing any compile-time validations.
This means that DECLARE_HANDLE(DPI_AWARENESS_CONTEXT)
will declare DPI_AWARENESS_CONTEXT
like this:
when STRICT
is defined:
struct DPI_AWARENESS_CONTEXT__{int unused;};
typedef struct DPI_AWARENESS_CONTEXT__ *DPI_AWARENESS_CONTEXT;
when STRICT
is not defined:
typedef void* DPI_AWARENESS_CONTEXT;
So, DPI_AWARENESS_CONTEXT
is declared as either a pointer to a record type or as an untyped pointer, depending on STRICT
.
That kind of name resolution cannot be translated to Delphi, since it does not support preprocessor macros like C/C++ does. The closest translation would be to declare DPI_AWARENESS_CONTEXT
directly instead:
type
{$IFDEF STRICT}
DPI_AWARENESS_CONTEXT__ = record
end;
DPI_AWARENESS_CONTEXT = ^DPI_AWARENESS_CONTEXT__;
{$ELSE}
DPI_AWARENESS_CONTEXT = Pointer;
{$ENDIF}
Or simply forget the existence of STRICT
altogether in Delphi:
type
DPI_AWARENESS_CONTEXT__ = record
end;
DPI_AWARENESS_CONTEXT = ^DPI_AWARENESS_CONTEXT__;
Either way, once DPI_AWARENESS_CONTEXT
is declared, you can then declare its constant values:
const
DPI_AWARENESS_CONTEXT_UNAWARE = DPI_AWARENESS_CONTEXT(-1);
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = DPI_AWARENESS_CONTEXT(-2);
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = DPI_AWARENESS_CONTEXT(-3);
Update: based on comments, you can alternatively use this instead:
type
DPI_AWARENESS_CONTEXT = type THandle;
const
DPI_AWARENESS_CONTEXT_UNAWARE = DPI_AWARENESS_CONTEXT(-1);
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = DPI_AWARENESS_CONTEXT(-2);
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = DPI_AWARENESS_CONTEXT(-3);
Note that these constants are only used for input to SetThreadDpiAwarenessContext()
, NOT for output from GetThreadDpiAwarenessContext()
. The latter returns an opaque handle to a private memory structure. You need to use GetAwarenessFromDpiAwarenessContext()
to retrieve the actual DPI_AWARENESS
value from that structure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With