Interface questions

Interface questions

I am currently modifying a windows/Fortran application to use Unicode text in all the menu's and dialogs and after a few technical issues this seems to be progressing OK.

The SDK has two versions of all routines that take text, for example WriteConsole is the generic but we have   WriteConsoleA (ansi text version) and  WriteConsoleW (Unicode text version). It seems that in all the IFWIN sub-sets the generic routine always interfaces to the A version and the W interface is always absent, As such I am having to provide my own interfaces, is there any plan to add these missing interfaces? It seems strange in this day and age  to have a Windows Fortran that does not support the method of choice for language support of windows!

My second question relates to the code snippet below from USER32.f90. The AppendMenu interface has AppendMenu_G1 and AppendMenu_G2 functions, does the compiler select which function to use based on the types of the arguments in the call?

INTERFACE AppendMenu

	FUNCTION AppendMenu_G1( &

	        hMenu, &

	        uFlags, &

	        uIDNewItem, &

	        lpNewItem)

	use ifwinty

	  integer(BOOL) :: AppendMenu_G1 ! BOOL

	    !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'AppendMenuA' :: AppendMenu_G1

	  integer(HANDLE) hMenu ! HMENU hMenu

	  integer(UINT) uFlags ! UINT uFlags

	  integer(UINT_PTR) uIDNewItem ! UINT_PTR uIDNewItem

	!DEC$ ATTRIBUTES REFERENCE, ALLOW_NULL :: lpNewItem

	  character*(*) lpNewItem ! LPCSTR lpNewItem

	 END FUNCTION

	FUNCTION AppendMenu_G2( &

	        hMenu, &

	        uFlags, &

	        uIDNewItem, &

	        lpNewItem)

	use ifwinty

	  integer(BOOL) :: AppendMenu_G2 ! BOOL

	    !DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'AppendMenuA' :: AppendMenu_G2

	  integer(HANDLE) hMenu ! HMENU hMenu

	  integer(UINT) uFlags ! UINT uFlags

	  integer(UINT_PTR) uIDNewItem ! UINT_PTR uIDNewItem

	  integer(LPVOID) lpNewItem ! LPCSTR lpNewItem

	 END FUNCTION

	END INTERFACE

3 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

For the unicode versions of Win32 API functions, there is the issue that ifort doesn't even have a unicode character type. gfortran, for example, has a second character type but it's a 4-byte character rather than the Windows 2-byte character. Also gfortran would have difficulties even with a 2-byte type because it uses C interoperability to invoke Win32 API functions and calling scenarios that work for default characters in f2003 don't work for nondefault character kinds. So whatever kinds of data structures you are using to contain wide characters, I doubt that ifort will offer support any time soon with interface bodies for wide character forms of the Win32 API functions.

As for the generic interface for the name AppendMenu, looking at the documentation, I observe that the normal way to invoke it seems to be with uFlags = MF_STRING in which case the lpNewItem is considered by the callee to be a pointer to an array of chars. Of course, C sees this as passing a pointer by value rather than an array or string by reference, so it could cast the value it received to an integer of kind LPVOID that is a bitmap handle (if uFlags = MF_BITMAP) or just some data to be passed along (if uFlags = MF_OWNERDRAW).

The generic interface doesn't tell the compiler which function to call because it calls AppendMenuA in either case. Rather it tells the compiler that if actual argument lpNewItem is of type character, to pass it by reference (i.e. pass the address of the character variable by value) and if it is integer of kind LPVOID, to pass it by value (so that what gets pushed on the stack or placed in register R9 in 64-bit mode is the value of the actual argument). Thus the compiler is not being told which function to call, but rather how to invoke the same function depending on the actual arguments.

You could get by with a single interface. If it specified a character*(*) by reference dummy, you could still pass an INTEGER(LPVOID) actual argument by stuffing its value into a Fortran pointer to character and passing the pointer (maybe %VAL with !DEC$ ATTRIBUTES NO_ARG_CHECK would also work). If it specified an INTEGER(LPVOID) by value dummy, you could pass an character actual argument by reference by taking its LOC (or a cray pointer) and passing that (would %REF + !DEC$ ATTRIBUTES NO_ARG_CHECK work in this case?)

 

@Repeat Offender

Thanks for the comments which are on the money. I am quite a way down the road with this now and largely having a whinge at Intel at the lack of Unicode support. I concluded that working with character types in Fortran had too many issues and have taken to working with null terminated integer(2) arrays for Unicode strings which is easier and perhaps more portable, this is what the C types effectively are anyway.. 

I have left IFWIN alone and created a separate module with interfaces to the missing xxxxW routines. To achieve some level of future proofing everything goes through a relatively small number of utility routines and wrappers that populate my string database from external Unicode text files and present these via functions to the appropriate routines within my code. This way if some more native support is forthcoming it will be quick and easy to update.

As far as the sdk is concerned I have interfaced to pass the integer(2) arrays by reference. The sdk is only interested in the start address and the null termination. I am not keen on Passing LOC(array) as standards checking whinges and the more compliant TRANSFER(C_LOC(.... is just clumsy looking and offends my eyes.

It is interesting that If Gfortran has 4 byte characters that would be to support the variable width UTF-8 encoding which has 1,2,3 or 4 bytes per characters which on average uses less bytes to present data and this it is favoured on the web.

 

 

Leave a Comment

Please sign in to add a comment. Not a member? Join today