Skip to content
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

Add Windows Version Helper functions #1050

Merged
merged 3 commits into from
Jan 10, 2019

Conversation

dbwiddis
Copy link
Contributor

@dbwiddis dbwiddis commented Jan 6, 2019

See reference docs. Code directly adapted from header file here.

Copy link
Member

@matthiasblaesing matthiasblaesing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a few comments inline. Thank you.

* If the function fails, the return value is zero and GetLastError
* returns an error code other than ERROR_OLD_WIN_VERSION.
*/
boolean VerifyVersionInfoW(OSVERSIONINFOEX lpVersionInformation, int dwTypeMask, long dwlConditionMask);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be VerifyVersionInfo -- but that would not work, because OSVERSIONINFOEX is only correctly bound for unicode?! Crap...

Copy link
Contributor Author

@dbwiddis dbwiddis Jan 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried VerifyVersionInfo but got UnsatisfiedLinkError: Error looking up function 'VerifyVersionInfo'. Both the W and A variants worked individually in this case because we're only using the numeric portions of OSVERSIONINFOEX. The inline functions in the header file use the W version, so that's the one I implemented. Should I add the A version as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er, now I see what you mean. This method should properly use OSVERSIONINFOEXW which is not defined (but the OSVERSIONINFOEX defined is the W version.)

I had to go look at git blame to make sure I wasn't at fault there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I'm thinking about the correct way to handle this. One thought was to copy the OSVERSIONINFOEX structure to OSVERSIONINFOEXW (have one extend the other) and mark the non-W version as deprecated. But there are many other functions which also call it, so we'd have to change all of them as well. Even though per the Windows documentation, all these old functions are also deprecated in favor of the Version Helper functions, which currently still refer to this structure... and around in circles we go.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see a good option to fix this without breaking API, so at this point in time, I think binding it as VerifyVersionInfoW is a good solution.

* dwTypeMask parameter indicates the members of this structure
* that contain information to compare.
*
* You must set the dwOSVersionInfoSize member of this structure
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to add p-tags to get the paragraph formatted (javadoc is HTML). The newlines are removed when rendered to HTML.

* behavior.
*
* @param lpVersionInformation
* A pointer to an OSVERSIONINFOEX structure containing the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be great if embedded code/code like sequences would be surrounded by {@code } and if possible @link to the class. That is not required, but people might like it :-)

byte VER_LESS = 4;
byte VER_LESS_EQUAL = 5;
byte VER_AND = 6;
byte VER_OR = 7;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a source/binary compatible change (will code compiled against 5.2 still work with 5.3 (or vice-versa)? I see why you do it, but if if is not compatible, please stay with int.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I searched the JNA codebase and don't see anywhere else where these constants are referenced.

External code using JNA 5.2 or earlier may use these as int, but a byte will work anywhere an int is expected with a widening conversion transparent to the user. The alternative is to require users to explicitly cast these all to byte to use them with VerSetConditionMask (and potentially other functions).

Given that byte-to-int happens transparently to the user, but int-to-byte requires an explicit cast, I do not think this breaks compatibility and byte is preferred here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well apparently it's not backwards compatible, which surprises me! But I'll put it back to int and then cast.

* @return true if the current OS version matches, or is greater than, the
* Windows XP version.
*/
public static boolean IsWindowsXPOrGreater() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether I like this, but I don't see a saner version, that doesn't look like repeats...

What might be worth evaluation is, if pulling HIBYTE(WinNT.WIN32_WINNT_WINXP) and LOBYTE(WinNT.WIN32_WINNT_WINXP) into private static final variables might be worth it.

Copy link
Contributor Author

@dbwiddis dbwiddis Jan 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did try to faithfully reproduce the existing inline header file, in the interest of readability.

I think adding variables would be worse than just explicitly doing the math ((byte) (word >>>8)) and (byte) word inline, which would be pre-calculated and optimized by the compiler. (I expect the JIT optimizer would also eventually optimize the method calls as well if they were called frequently enough.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry! I did not realize, that I had looked at an older SDK, that did not contain the header. And I just realized, that you linked the header. Your first version was better readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you want me to go back to the HIBYTE and LOBYTE methods (that would be JIT optimized) rather than the current compiler-optimized bit math? I kind of like the current version and think adding a comment would make it just as readable/understandable for future maintainers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking was, that at this time I understand what you are doing there. But in 6-12 months I might have a WTF moment. I'm ok if you want to keep the bit shifts inline.

Independend of this - my original idea was this:

    private static final byte WIN32_WINNT_WINXP_MAJOR = HIBYTE(WinNT.WIN32_WINNT_WINXP);
    private static final byte WIN32_WINNT_WINXP_MINOR = LOBYTE(WinNT.WIN32_WINNT_WINXP);
    /**
     * @return true if the current OS version matches, or is greater than, the
     *         Windows XP version.
     */
    public static boolean IsWindowsXPOrGreater() {
        return IsWindowsVersionOrGreater(WIN32_WINNT_WINXP_MAJOR, WIN32_WINNT_WINXP_MINOR, 0);
    }

Pulling the calculation into a static final. But as said, if you like it this way, I won't stand in the way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add a comment explaining what the bit shifts do, so you and I both can remember what's going on in 6-12 months.

@@ -7,6 +7,7 @@ Next release (5.2.1)

Features
--------
* [#1050](https://github.com/java-native-access/jna/pull/1050): Add `c.s.j.p.win32.VersionHelpers` and supporting functions - [@dbwiddis](https://github.com/dbwiddis).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the version behind "Next release" to "5.3.0", as it will be a feature release with this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought so and somewhat expected this comment. :)

@@ -0,0 +1,66 @@
package com.sun.jna.platform.win32;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed this in the first round - could you please also the ALv2+LGPL header here? I'd like to converge on that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do! I just copied some other random test file that was missing a header so didn't know if that was standard.

@matthiasblaesing
Copy link
Member

Thank you - merging.

@matthiasblaesing matthiasblaesing merged commit 9a1be16 into java-native-access:master Jan 10, 2019
@dbwiddis dbwiddis deleted the version-helper branch February 4, 2019 17:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants