Lightweight 0.20260921.0
Loading...
Searching...
No Matches
SqlOdbcPrelude.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5// This header exists so that every Lightweight header needing <sql.h>/<sqlext.h>/<sqlspi.h>/
6// <sqltypes.h> on Windows can include *this* instead of the full <Windows.h> SDK aggregate.
7//
8// Investigation (see https://github.com/LASTRADA-Software/Lightweight/issues/547): the Windows
9// ODBC headers are not self-contained. <sqltypes.h> unconditionally declares
10// `typedef HWND SQLHWND;` on WIN32 (needed only so ODBC's connection-prompt APIs can carry an
11// optional owner window — Lightweight always passes `(SQLHWND) nullptr`, see
12// SqlConnection.cpp's SQLDriverConnectW call, and never dereferences it), and `typedef GUID
13// SQLGUID;` guarded by GUID_DEFINED. <sqlext.h>'s legacy, Windows-8-removed Visual-Studio-tracing
14// section (ODBC_VS_ARGS/FireVSDebugEvent) additionally references BOOL/DWORD/VOID/WCHAR/CHAR/
15// LPWSTR. None of these are otherwise used by Lightweight (grep confirms: only prose comments and
16// the library's own distinct SqlGuid type mention "GUID"); previously the full <Windows.h>
17// prelude was pulled in just so the *parser* could get past these unconditional declarations.
18//
19// Below are the minimal, ABI-stable shapes the Windows SDK's own headers use internally for these
20// symbols (HWND from <um/winuser.h>'s DECLARE_HANDLE expansion; GUID from <shared/guiddef.h>;
21// the rest from <shared/minwindef.h>/<shared/winnt.h>). Defining them here — rather than
22// including <Windows.h> — avoids pulling in the ~150k-line SDK aggregate (macro pollution beyond
23// min/max, compile-time cost, and the ODR/ABI surface of everything Windows.h drags in) while
24// still letting <sql.h> and friends parse.
25//
26// @warning These typedefs must stay byte-identical to the Windows SDK's own definitions: if a
27// consumer's translation unit also includes <Windows.h> (directly or transitively) after this
28// header, the two must be identical or the second one is a hard redefinition error. If a future
29// Windows SDK version adds a new symbol reference to a deprecated/legacy section of <sql.h>/
30// <sqlext.h>/<sqlspi.h>/<sqltypes.h> that isn't covered below, the fix is to extend this file with
31// that symbol's own minimal shape — not to fall back to <Windows.h>.
32#if defined(_WIN32) || defined(_WIN64)
33
34 // Guards <Windows.h>'s own min/max function-like macros from leaking into every consumer TU
35 // that includes this header (directly or transitively) and breaking any later std::min/
36 // std::max/std::numeric_limits<T>::min()/max() call in the same TU (#542). These only take
37 // effect if the consumer later includes the real <Windows.h> themselves; defined only if not
38 // already picked, so an application-wide override still wins.
39 #ifndef NOMINMAX
40 #define NOMINMAX
41 #endif
42 #ifndef WIN32_LEAN_AND_MEAN
43 #define WIN32_LEAN_AND_MEAN
44 #endif
45
46// HWND has no symbol-level include guard in the real SDK (only windef.h's own file guard), but
47// a repeated identical forward-declaration + typedef is legal C++, so this is safe even if a
48// consumer's TU later includes the real <Windows.h> too.
49struct HWND__;
50typedef struct HWND__* HWND; // NOLINT(modernize-use-using): mirrors <um/windef.h>'s own typedef.
51
52 #ifndef GUID_DEFINED
53 #define GUID_DEFINED
54typedef struct _GUID // NOLINT(modernize-use-using): mirrors <shared/guiddef.h>'s own typedef.
55{
56 unsigned long Data1;
57 unsigned short Data2;
58 unsigned short Data3;
59 unsigned char Data4[8];
60} GUID;
61 #endif
62
63 #ifndef _MINWINDEF_SHIM_DEFINED
64 #define _MINWINDEF_SHIM_DEFINED
65using BOOL = int;
66using DWORD = unsigned long;
67using WCHAR = wchar_t;
68using LPWSTR = WCHAR*;
69 #endif
70
71 // <um/winnt.h> gates VOID/CHAR/SHORT/LONG/INT as ONE atomic bundle behind a single
72 // `#ifndef VOID` (not one guard per symbol): defining VOID alone here would make a later
73 // real <Windows.h> skip the whole bundle's #ifndef body, silently leaving CHAR/SHORT/LONG/INT
74 // undefined — which is exactly what broke winnt.h's PLONG-using interlocked-intrinsics section
75 // (#547). Reproduce the full bundle atomically so a later winnt.h's #ifndef VOID correctly
76 // finds everything already defined and skips cleanly, instead of partially pre-empting it.
77 #ifndef VOID
78 #define VOID void
79using CHAR = char;
80using SHORT = short;
81using LONG = long;
82 #if !defined(MIDL_PASS)
83using INT = int;
84 #endif
85 #endif
86
87 #include <basetsd.h>
88 #include <sal.h>
89 #include <winapifamily.h>
90#endif