Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

WIN API Constant Types

pjh_gn
Beginner
1,774 Views

I have been trying to use the MakeLangID Windows API call using IVF 9.1 and have been getting a warning about incorrect data types. On Further investigation I found that the language definitionconstants (LANG_NEUTRAL etc)in IFWINTY.F90 are declared as (native) integer type (ie 4-Byte on my system), whereas the arguments for the MakeLangID interface (as defined in IFWBASE.F90), are 2-Byte, which matches the macro definition inWINNT.H (defined as USHORT).

To complicate things further the result from MakeLangID is also a 2-Byte integer (in IFWBASE.F90), but the dwLanguageID input to FormatMessage is 4-Byte (DWORD in KERNEL32.F90).

Can anyone shed any clarity on this mess? There is obviously no real problem as the intrinsic integer type-casts work OK in both API calls, but it is irritating getting the error messages. To get around this I have defined local 2-byte versions of the constants and done the type cast on the MakeLangID function return variable (which doesn't give a compiler warning - what the eye doesn't see the heart doesn't grieve over).

Maybe the IFWINTY.F90 file should be changed to accuratelymatch all 2-Byte integer #defines in the matching c header files?

0 Kudos
14 Replies
Steven_L_Intel1
Employee
1,774 Views

This is just part of a larger problem that surfaced when we fixed the bug that had the compiler quietly converting mismatched datatypes in the presence of an explicit interface. Unfortunately, it is not as simple as just declaring the constants the right type, as sometimes they need to be int2 and sometimes int4.

I have a proposal to add a new attribute that could be added to interface blocks that says "ignore the kind of constants passed to this argument" (doing a convert if needed). It has not been implemented yet. We'd then add this to all appropriate Win32 API interfaces.

0 Kudos
pjh_gn
Beginner
1,774 Views

Thanks Steve.

Your proposalseems to be a sticking plaster solution rather than a proper fix. Messing with the interface block to allow the user to pass an incorrect type is too much like C and not enough like Pascal for my taste.

In this particular case I think it should be the user's responsibility to do the integer type cast between MakeLangID output (2-byte) and the FormatMessage input (4-byte), because that is the way Microsoft have defined the API. The problem I had in doing this is the IFWINTY definitions for the language constants are in the "wrong" type (in relation to their equivalent definition in WINNT.H). This means I had to do another integer type cast to get the constants into MakeLangID.

I have now sorted things out by writing my own version of MakeLangID, which at the end of the day is only a #define macro that concatenates a pair of 2-byte integers. I have written 2-byte and 4-byte dummy argument versions with a generic interface so that it will work with constants definined in either integer types. If anyone is interested,the source is below- any comments for improvement would be appreciated.My user defined bitwise operators can be replaced simply by ISHFT and IOR procedure calls.

MODULE

xxx_WINNTL

IMPLICIT NONE

! A language ID is a 16 bit value which is the combination of a

! primary language ID and a secondary language ID. The bits are

! allocated as follows:

! +-----------------------+-------------------------+

! | Sublanguage ID | Primary Language ID |

! +-----------------------+-------------------------+

! 15 109 0 bit

! Language ID creation/extraction macros:

! MAKELANGID - construct language id from a primary language id and

! a sublanguage id.

! PRIMARYLANGID - extract primary language id from a language id.

! SUBLANGID - extract sublanguage id from a language id.

INTERFACE xxx_MAKELANGID

MODULE PROCEDURE SHORT_MAKELANGID, LONG_MAKELANGID

END INTERFACE

CONTAINS

FUNCTION SHORT_MAKELANGID(jPRIMLANG, jSUBLANG) RESULT(iLANGID)

! Creates a 4-byte Language ID from user input 2-byte primary

! and sub-language IDs

USE xxx_BITOPERATORS, ONLY: OPERATOR(.SHL.), OPERATOR(.IOR.)

USE IFWINTY, ONLY: USHORT, ULONG

INTEGER(USHORT), INTENT(IN) :: jPRIMLANG, jSUBLANG

INTEGER(ULONG) :: iLANGID

INTEGER(USHORT) :: jLANGID

! Create 2-byte language ID

jLANGID = (jSUBLANG .SHL. 10) .IOR. jPRIMLANG

! Do Integer type cast 2-bytes to 4-bytes

iLANGID = INT(jLANGID,ULONG)

END FUNCTION SHORT_MAKELANGID

FUNCTION LONG_MAKELANGID(iPRIMLANG, iSUBLANG) RESULT(iLANGID)

! Creates a 4-byte Language ID from user input 4-byte primary and sub-language IDs

USE xxx_BITOPERATORS, ONLY: OPERATOR(.SHL.), OPERATOR(.IOR.)

USE IFWINTY, ONLY: ULONG

INTEGER(ULONG), INTENT(IN) :: iPRIMLANG, iSUBLANG

INTEGER(ULONG) :: iLANGID

! Create 2-byte language ID

iLANGID = (iSUBLANG .SHL. 10) .IOR. iPRIMLANG

END FUNCTION LONG_MAKELANGID

END MODULE

xxx_WINNTL

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,774 Views

Steve,

While you are in messing around with interface blocks it would be handy (for me) if one could declare an interface block where the ATTRIBUTES VALUE could be promoted or demoted without error if the compiler can determine if no loss in precision or with warning when it cannot.

!DEC$ ATTRIBUTES VALUE appropriateKeyWord :: foo
integer :: foo

In this way an int2 parameter can be happily passed as int3 or int8 as the case may be.

I recently converted an app from 32-bit to 64-bit and found it a bit of a pain making permutation number of interfaces just to handle integer promotion/demotion.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,774 Views

My proposal would cover that case, Jim. The bigger problem we have is with some routines (RGB, for example) which take INTEGER(1) arguments and a typical call would be RGB(255,255,255). First of all, those 255s are INTEGER(4) by default. Second, you can't say 255_1 because that's not a valid value for that kind. CVF quietly passed the 4-byte 255 but now we have lots of programs that don't compile without some very kludgy-looking code (using TRANSFER, for example).

There are two things we need to do. One is to find APIs where integer IN arguments are 1 or2 bytes and fix it so that one can pass a 4-byte integer safely. We also need to look at PARAMETER constants with kinds that don't match the corresponding API. Unfortunately, some of them seem to be used with two different integer kinds! It's a mess.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,774 Views

It is a mess - need some Advil?

My personal preference isthe fix could be made to the interface block as opposed to requireing editing of the calls using the interface. Permit the promotion/demotion of integers when instructed to do so (via !DEC$ ATTRIBUTES...)and add Debug runtime checking optionthat asserts on data loss. i.e. either

a) the sign bit of the precision of the argument used by the subroutine matches the bits in excess of the bits used by the subroutine argument (strong test). This asserts that MOVSX or other proper sign extension was used.

b) the bits in excess of those used by the subroutine are either all 1's or all 0's (weaker test).

What I think is really uggly is specifying64 different interfaces to handle

SUBROUTINE COLOR(R, G, B)

Where perfectly valid integers of 1, 2, 4, 8 bytes are passed. Those who want strong type checking can code to use strong type checking, those that prefer more flexible type checking can be permitted to use more flexible type checking.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,774 Views
Yes, this proposal is to add an attribute that goes in the interface block so that user code doesn't need to change. We have done that in the past with such attributes as ALLOW_NULL and IGNORE_LOC.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,774 Views

I've used NO_ARG_CHECK but this is too weak as it passes things you'd rather it not pass. The biggest problem is getting the suggestion past the standards committee person. Might I suggest the tact to take is instead of:

Requesting an option to weaken the interface (standard progressing towards weak control)

rephrase the request as

Requesting an option to strengthen the interface over the use of NO_ARG_CHECK (standard progressing towards strong control)

Jim

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,774 Views
...which reminds me of an internal joke in our company: when we (developers) used the phrase "OK, we'll kludge the code so that it works", our boss jokingly come out with the euphemism "better use the term strengthen instead". The joke caught up, so now we all strengthen our codes... Smiley with tongue out [:-P]
0 Kudos
g_f_thomas
Beginner
1,774 Views
0 Kudos
Steven_L_Intel1
Employee
1,774 Views

We decided on a different approach. We're going to go back to quietly doing the conversion on integer constants when there is an explicit interface specifying a different integer kind. If you ask for standards checking, you'll get a warning and a mismatch won't resolve a generic reference.

I did change the types of the LANG_ constants, though the winbase.h defines aren't really typed.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,774 Views

Could that be extended a tad to promote INTENT(IN) as well as integer constants?

If the integer variable on INTENT(IN) is promoted (to a larger storage size) then have ittreated as an expression whereby the promoted temporary (of proper size) is created on the stack. Demotion is ok to use same reference. If the interface specifies by value then the promotion is moot (already done).

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,774 Views
I don't think so. The primary motivation for this was for code that uses integer constants, especially those in the "unsigned range". With variables, it is much easier to specify the proper type.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,774 Views

Steve,

In many cases, in order to specify the proper type you have to create a temporary. e.g. if the default integer size is 4 but the routine takes an integer size 2 you have to create a temporary and equate the variable over. You cannot even use the larger integer in an expression to the sub/func. Yes, there is the problem of args of reference that get modified and there I see enforcement of type a requirement. integer IN args can get temp-ed if necessary by the compiler. No different than for constants.

As a side note. You are permitted to specify an array section as an argument to a subroutine or function. When the array section is not directly mappable then a temporary array is created, data copied, sub/func called, data copied back, temporary array deleted. This occurs transparently to the programmer (excepting for longer execution time). This conversion is significantly more difficult to perform than the simple integer conversion that I suggest you consider. Yet, I cannot consider that the two circumstances are not functionally equivalent.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,774 Views

Jim,

With a variable, it's easy to use a type conversion intrinsic such as INT(x,2) or whatever. I don't think we'd be doing any favors by extending the conversion behavior past what we're planning, which is intended to help with use of literal constants.

0 Kudos
Reply