-
Notifications
You must be signed in to change notification settings - Fork 125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BITMAPINFOHEADER biCompression flag inconsistencies #1442
Comments
We have no control over .NET definitions here. Is the win32metadata representation correct? Is the main problem that FOURCC codes effectively represent an open set, so using a closed set enum at all for this field is not appropriate? |
What I had initially ran into was the int versus uint type mismatch. However that led me to notice these fields were inconsistently defined. Since I'm just working at the level of the projection I'm not sure how far upstream this should be addressed. |
@AArnott what are your thoughts on this? From the report, it sounds like .NET types we don't control are incorrect, and the metadata we publish is correct. |
Is that a reference to private code in the runtime? Matching that is not a goal, nor is it expected to present a conflict to the .NET user because they don't have access to that class.
If that's a reference to win32metadata, I cannot find that namespace or type. I'm looking at 40.0.14-preview of the metadata.
What is "Standard"? Can you provide the library and full API name? Ultimately though, the win32metadata's goal is to match the headers, with a little semantic richness added (e.g. add enums where appropriate). Since the headers define @mikebattista I notice in the documentation the reference to |
What I had done to find these values:
That left me with these remaining results: System.Drawing.NativeMethods+BITMAPINFOHEADER.biCompression :
Windows.Win32.DirectShow.BITMAPINFOHEADER.biCompression :
Standard.BITMAPINFOHEADER.biCompression :
Standard.BI :
Apologies if this is not the best way to look into this, I was attempting to follow the advice in the README.md but I'm not familiar with this utility. |
In the latest metadata it's an enum: // Windows.Win32.Graphics.Gdi.BITMAPINFOHEADER
public BI_COMPRESSION biCompression;
// Windows.Win32.Graphics.Gdi.BI_COMPRESSION
public enum BI_COMPRESSION
{
BI_RGB,
BI_RLE8,
BI_RLE4,
BI_BITFIELDS,
BI_JPEG,
BI_PNG
} EDIT: There is also // Windows.Win32.Media.KernelStreaming.KS_BITMAPINFOHEADER
public uint biCompression; |
@mikebattista I'm not familiar with the semantics chosen for metadata when it comes to parameters with enumeration types. If it is meant to convey to consumers that there is a closed set of values then yes, we should change this back to a I ask because C# allows for |
Because of the ability of this field to hold FOURCC values, it appears to be an open set. Thus it would seem that it should be defined as However, there are also predefined values that would have normally been an enum if it were a closed set. Because of this would it make sense to ALSO define the constants that normally would have been an enum, but just define them as uints? In this way the values will be readily available for assignment by name while still keeping it an open set. For example:
(Values based on https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57) |
At least for C++ and Rust you can use an enum here and still support an open-ended set by placing a different value into the enum. And it seems C# supports this as well. #1442 (comment) |
@kennykerr I'm glad you spoke up, because I was about to say I thought rust required enums to be a closed set. |
@mdepot When you open the metadata in ILSpy, ILSpy will automatically open a bunch of reference assemblies as well. Most of the search results you shared come from other assemblies, which are irrelevant as they are private to those assemblies and win32metadata does not attempt to match them. |
Yes, I don't really see the value in that distinction. It's all the same to me and I end up having to normalize them on my end where everything ends up open-ended and represented the same way. |
In ILSpy, you can go to |
I'm fine keeping this as an enum. In which case, what are the pending changes? Just also applying the enum to KS_BITMAPINFOHEADER? Does the enum contain all the values it should? |
I submitted a PR to return it to I don't think we can assume all languages (current or future) will support open-ended enums. For example, I haven't used Dart much but I couldn't quite figure out how to make this work nicely over there. (Maybe Dart's enhanced enums would come into play here?) Duplicate discussion: #261 |
cc @timsneath |
From a Dart perspective, I'm fine with this being an enum, although I'd love to see some metadata marker to identify enums that are open-ended. Enhanced enums could work, but I want to explore using the new inline class feature in Dart 3 for this kind of value. |
Thank you for highlighting this. I am currently using this projection for Go. In Go the common way to handle enums (today) is to define a custom type, and then create constants of that type representing the possible values. There is a proposal to enhance how enums work in Go, but that's still a work in progress. While it may be possible to define more constants of that type later, doing so would split the definition of possible values into different areas of code maintained by different people. |
In general we have used enums for closed sets which follows the .NET design guidelines. The conclusion of #261 was not to use an enum for that reason (though somewhere along the way looks like an enum was mapped to this open set field). I'm open to using enums for open sets if there's a proposal that works for all languages. |
Is there an attribute that could be used/repurposed to indicate whether a set is open or closed? Then projections who treat them all as open can simply ignore it whereas those who want to do something special can do so. |
Not currently but we could create one if that would work for everyone. If we did that, I would say that absence of the attribute indicates closed, and presence of the attribute indicates open. |
I like the idea of having the attribute, but a single open/closed flag would only indicate two use cases. We actually have three. The simple cases are a closed set with a defined set of known values for the enumeration, and open set with no defined set of values at all. Then there is this third middle ground case of an open set that additionally has a number of known values defined that can be assigned. Before deciding on how this new attribute should be implemented, it may make sense to first decide on how this third use case should be handled. Above I proposed not using an enum but also defining any known members of the open set as constants. Does it make sense for that to be the standard for all instances of this third case scenario? Are there alternatives? I think only after this is decided upon does it make sense to design how a new attribute should work, as it's likely dependent on how this third case is to be handled, |
We have never used enums for this. We use typedefs for some of these (where the native code does). |
On thinking about this further, I can see that having the typedef plus an open/closed set flag would be enough for a projection to decide if it should actually implement the set with an enum or not in the projection's target language. As a simple user of a projection, the responsibility of whether that decision should happen in the metadata or the projection was not clear to me at first. |
What should the attribute be named? |
In the interest of keeping things simple and moving, I vote for just correcting biCompression ( |
The BITMAPINFOHEADER structure contains a DWORD biCompression field. There seems to be a number of closely related issues with how this field is defined in win32metadata.
First of all, the biCompression field is defined inconsistently, in three different ways. In System.Drawing.NativeMethods it's an int, while in Windows.Win32.DirectShow it's a uint, and finally in Standard it's an enumeration of type BI.
This page https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader says the biCompression field is supposed to be able to hold either a FOURCC code (for compressed formats) or a number of defined flags (for uncompressed formats). And this page https://learn.microsoft.com/en-us/windows/win32/directshow/fourcc-codes says a FOURCC code is a 32-bit unsigned integer.
There is also a problem with the way the BI_* flag values meant to be assigned to the biCompression are defined. MS.Win32.NativeMethods has a single BI_* constant defined (BI_RGB), and is missing at least the BI_BITFIELDS flag. However System.Drawing.NativeMethods has it's own BI_* constants, this time for both BI_RGB and BI_BITFIELDS. And finally, the BI enumeration in Standard only has RGB defined. Based on this page https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4e588f70-bd92-4a6f-b77f-35d0feaf7a57 from the WMF docs, it looks as if there are nine possible values for this that should be defined.
It would seem that all three definitions of biCompression should at least be consistent with each other, and perhaps they should also all be based on a more fully flushed out uint based BI enumeration as well.
Without at least fixing the type consistency, a projection may allow for assigning the int based BI_RGB to the uint biCompression field defined in Windows.Win32.DirectShow, resulting in a type mismatch error, which is how I found this.
The text was updated successfully, but these errors were encountered: