CsWin32: Could not load type "that is incorrectly aligned or overlapped by a non-object field"
Actual behavior
When I import the PROPVARIANT
type, the type is not declared property and throws a TypeLoadException
when referenced. The error message is “Could not load type __Anonymous_e__Union from assembly ‘…’ because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.”
Expected behavior
Type should work.
Repro steps
NativeMethods.txt
content:
PROPVARIANT
IPropertyStore
SHGetPropertyStoreForWindow
NativeMethods.json
content:
{
"$schema": "https://aka.ms/CsWin32.schema.json",
"className": "NativeMethods",
"namespace": "Windows.Win32",
"wideCharOnly": true
}
- Any of your own code that should be shared?
This is the class that references the broken type:
Context
- CsWin32 version: 0.1.422-beta
- Win32Metadata version: not explicitly set
- Target Framework: net5.0-windows
LangVersion
: 9
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 1
- Comments: 18 (16 by maintainers)
Commits related to this issue
- Add failing (and skipped) test to repro #292 — committed to microsoft/CsWin32 by AArnott 2 years ago
- Force unmarshaled fields in union structs Fixes #292 — committed to microsoft/CsWin32 by AArnott 2 years ago
We should probably keep this active to track the bug when
allowMarshaling: true
, yes?This would just be defining 100% blittable data types (which is what TerraFX.Interop.Windows does). Anything else is a “convenience wrapper” on top of this that deals with things like pinning, marshalling, etc (which is what
DllImport Source Generator
is responsible for generating from a given non-blittable interop signature).The way I handle this in TerraFX.Interop.Windows: https://source.terrafx.dev/#TerraFX.Interop.Windows/Windows/um/oaidl/ITypeComp.cs,5a439f56db1bf1c9
There is the base struct:
Various helper methods exposing the VTBL members and account for ABI differences (returning
HRESULT
isn’t ABI compatible, so you’ll note that the fnptr returnsint
and there is an implicit conversion to the user friendly type):An interface defining the required exposed members and the inheritance heirarchy:
and finally a VTBL declaration for convenience:
All of these combined allow robust and convenient access/usability of the types and data, even while being
unsafe
. There are various attributs likeVtblIndex
andNativeTypeName
which track “lost metadata” represented in C/C++ and which are stripped in Release builds.The data is already not blittable and so is already incompatible with native code. The built-in marshalling system isn’t really recommended for “new code”, the
DllImport Source Generator
is going to be the recommended thing moving forward.But in either case, the built-in marshalling system can’t support such a definition anyways because the type system fundamentally doesn’t support it. You will have to define and implement manual marshalling here if your type is both a union and that union contains any reference types.
You cannot union a value and reference type. You really shouldn’t union incompatible reference types (its akin to
Unsafe.As<T>(object obj)
and is undefined behavior whenobj
isn’t actually aT
).At a minimum you’re going to need to break it apart so that the value and reference types aren’t overlapping, and you’ll need to handle that as part of the marshalling logic.
@AArnott Looking around on the interweb, VC compiler & GCC appear to pick the size of the largest union field, ie the size of that union will always be pointer size (before factoring in padding).
That did it! Thanks!