- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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_WINNTLIMPLICIT 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_MAKELANGIDMODULE PROCEDURE SHORT_MAKELANGID, LONG_MAKELANGIDEND INTERFACECONTAINS
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, ULONGINTEGER(USHORT), INTENT(IN) :: jPRIMLANG, jSUBLANGINTEGER(ULONG) :: iLANGIDINTEGER(USHORT) :: jLANGID! Create 2-byte language IDjLANGID = (jSUBLANG .SHL. 10) .IOR. jPRIMLANG
! Do Integer type cast 2-bytes to 4-bytesiLANGID = INT(jLANGID,ULONG)
END FUNCTION SHORT_MAKELANGIDFUNCTION LONG_MAKELANGID(iPRIMLANG, iSUBLANG) RESULT(iLANGID)! Creates a 4-byte Language ID from user input 4-byte primary and sub-language IDsUSE xxx_BITOPERATORS, ONLY: OPERATOR(.SHL.), OPERATOR(.IOR.)USE IFWINTY, ONLY: ULONGINTEGER(ULONG), INTENT(IN) :: iPRIMLANG, iSUBLANGINTEGER(ULONG) :: iLANGID! Create 2-byte language IDiLANGID = (iSUBLANG .SHL. 10) .IOR. iPRIMLANG
END FUNCTION LONG_MAKELANGIDEND MODULE
xxx_WINNTL
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
![Smiley with tongue out [:-P]](/ISN/Community/en-US/emoticons/emotion-4.gif)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page