Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner

EnumFontFamiliesEx fails under 32bit but fine under 64bit

Jump to solution

Hi,

I'm using EnumFontFamiliesEx from ifwin to find the font names on the users computer.

I have the following code:

   != Process reading the Fonts on this PC
     integer function enum_fonts(lFont, pFont, fType, lParam)
        use ifwin
        implicit none
        type (T_ENUMLOGFONTEX) :: lFont
        type (T_NEWTEXTMETRICEX) :: pFont
        integer(DWORD) :: fType
        integer(LONG_PTR) :: lParam
        integer :: i,len,c

       enum_fonts = 1    
       if (npcfonts .lt. MAXPCFNT) then    
       npcfonts = npcfonts + 1
       pcfonts(npcfonts) = lFont%elfFullName(1:FNTLEN)
       do i = 2,FNTLEN ! Remove null termination
          c = ichar(pcfonts(npcfonts)(i:i))
          if (c .eq. 0) then
             pcfonts(npcfonts)(i:FNTLEN) = ' '
             return
          endif
       enddo
     endif
     end function enum_fonts

    != Read the Fonts on this PC
      subroutine GetPCFonts()
        use ifwin
        implicit none
        integer(HANDLE) hdc
     type (T_LOGFONT) LogFont;
        integer :: ret
     
        hdc = GetDC(0)
        LogFont%lfCharSet = ANSI_CHARSET
        LogFont%lfPitchAndFamily = 0
        LogFont%lfFaceName = ' '
        LogFont%lfFaceName(1:1) = achar(0)
     npcfonts = 0
     ret = EnumFontFamiliesEx(hdc,LogFont,%REF(enum_fonts),0,0)
        return    
      end subroutine GetPCFonts

Note npcfonts, pcfonts, FNTLEN(=32) and MAXPCFNT(=1024) are at the module level.
This runs as expected on the 64bit version, giving me 303 fonts on my PC
but in the 32bit version it only returns 1 font. I can't see why it's working in
one case and not the other as the integer default is 4 in both cases and
the declarations see fine otherwise, and I'm always returning 1 from
enum_fonts to continue enumeration.

Thanks for any help,
David.

Note: I'm using Intel(R) Visual Fortran Composer XE 2013 SP1 Update 6 Integration for Microsoft Visual Studio* 2008, 14.0.0100.2008, Copyright (C) 2002-2014 Intel Corporation as we haven't validated our software under a later version yet.

Also I can't find any recorded bug fixes for EnumFontFamiliesEx.

0 Kudos

Accepted Solutions
Highlighted

All Windows API callback

Jump to solution

All Windows API callback functions must use the STDCALL calling convention. On Intel 64 this doesn't matter, but it does on IA-32. Also, your callback routine doesn't specify that the last two arguments are passed by value.

Try this.In your callback routine, add:

!DEC$ ATTRIBUTES STDCALL, REFERENCE ::enum_fonts
!DEC$ ATTRIBUTES VALUE :: ftype, lParam

I did this and it works.

Retired 12/31/2016

View solution in original post

0 Kudos
13 Replies
Highlighted
1 View

All Windows API callback

Jump to solution

All Windows API callback functions must use the STDCALL calling convention. On Intel 64 this doesn't matter, but it does on IA-32. Also, your callback routine doesn't specify that the last two arguments are passed by value.

Try this.In your callback routine, add:

!DEC$ ATTRIBUTES STDCALL, REFERENCE ::enum_fonts
!DEC$ ATTRIBUTES VALUE :: ftype, lParam

I did this and it works.

Retired 12/31/2016

View solution in original post

0 Kudos
Highlighted
Beginner

Thanks so much Steve, that's

Jump to solution

Thanks so much Steve, that's gold, very much appreciated. 

I've been looking but can't find much documentation on the ifwin library beyond three pages in the help, which don't give any details like this.

Is there a document that goes into more detail?

0 Kudos
Highlighted

MSDN Library

Jump to solution
0 Kudos
Highlighted
Beginner

Thanks, I'm very familar with

Jump to solution

Thanks, I'm very familar with the Windows Platform SDK, what I need is a document that shows how to declare the calls on the Fortran side.
 reading ifwinty.f90 gives me most of what I need but not the information on declaring the callbacks. Your comment gives me a good start. I've read the Using Intel® Visual Fortran to Create and Build Windows*-Based Applications but it's pretty lightweight, not the full reference manual I was hoping for. Thanks again, much appreciated.

0 Kudos
Highlighted

MSDN is the "full reference

Jump to solution

MSDN is the "full reference manual". There are also lots of examples we provide. It's not really possible for us to describe how to use each and every API routine from Fortran - the best we can do is some general guidelines. I'll admit that the STDCALL requirement for callbacks can be obscure, but it's a fundamental aspect of Windows API programming.

There once was a book "Compaq Visual Fortran: A Guide to Creating Windows Applications" that went into this topic in great detail. It is still mostly applicable to Intel Visual Fortran, but it hasn't been published in a while and copies are expensive.

You might want to start with https://msdn.microsoft.com/library/windows/desktop/ff381399(v=vs.85).aspx - while this is C++ oriented, a lot of the text is generally applicable to Fortran. Even here, though, the need for STDCALL is obscure - possibly because this is hidden in the C++ header files. We've started to add abstract interfaces for callbacks to our modules, specifying STDCALL, so that may help, but it wouldn't have helped you here. Luckily, once you become aware of this it becomes second-nature. And, as I said, it is a 32-bit issue only since on x64 there is only one calling convention.

Retired 12/31/2016
0 Kudos
Highlighted
New Contributor II

David,

the Lawrence book is still available. Amazon ask prices up to USD 80, our local Dutch (book)store (bol.com) has a price euro 60. You can obtain the examples of the book via the site  http://booksite.elsevier.com/9781555582494/

Unfortunately, the book is out-of-data. It is published in 2002 and thus has not used Fortran 2003 with its ISO_C_BINDING.stuff. It thus does not show you how to wrtite a window program in a strict standard-conforming and compiler-independent way. It uses the Compaq compiler now known as  Intel. The Fortran introduction  aspect is the weak point. But there are a number of more advanced topics that are handled very well. For that reason I can recomment it. (Of course, always besides the Petzold book!)

Robert

0 Kudos
Highlighted

There isn't a way to write a

Jump to solution

There isn't a way to write a Windows API program in a compiler-independent way. You can generally avoid nonstandard code in your own application with some effort. The Lawrence book is still very applicable.

Retired 12/31/2016
0 Kudos
Highlighted
Beginner

Thanks everyone for the input

Jump to solution

Thanks everyone for the input, I've ordered a copy from Better World Books who sell second hand books and have free shipping to any country:
http://www.betterworldbooks.com/Compaq-Visual-FORTRAN--A-Guide-to-Creating-Windows-Applications-id-9...
Mine cost US$31 including shipping. Better Wortd also donate a book to charity for each one you buy.

0 Kudos
Highlighted
New Contributor II

In my post #7 I was not clear

Jump to solution

In my post #7 I was not clear. With "compiler-independent" I did mean the situation of having only one Fortran file(or set of files) that can be used in combination with more that one compiler. My experience with the WinAPI, OpenGL, freeglut is that for 64 bits it always works fine. For 32 bits you need to add directives. A drawback, of course, is that you have to write yourself a module with the named constants, structs and interfaces .

Robert

0 Kudos
Highlighted
Valued Contributor II

The nice thing is that !DEC$

Jump to solution

The nice thing is that !DEC$ ATTRIBUTES STDCALL and !GCC$ ATTRIBUTES STDCALL are pretty much compatible for procedures with the BIND attribute, so a single source with both ATTRIBUTES declarations generally works fine in both gfortran and ifort, 32 bits and 64 bits. The worst incompatibility I can recall is that C_LONG ends up being 8 in cygwin, so Windows data types that are dependent on this constant should be made dependent on another constant for Windows code intended for use in cygwin. Doesn't Windows C code potentially suffer for the same problem with Windows header files?

 

0 Kudos
Highlighted

I don't see how C_LONG can

Jump to solution

I don't see how C_LONG can change based on using Cygwin - at least using Intel Fortran. Maybe gfortran handles it differently.

In Intel Fortran, using our modules, you'd be using named constants such as DWORD that always are the right kind. Windows C code would similarly be using typedefs declared in windows.h.

Retired 12/31/2016
0 Kudos
Highlighted
Valued Contributor II

The issue is that if you look

Jump to solution

The issue is that if you look in https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx it says that DWORD is defined in IntSafe.h as typedef unsigned long DWORD; and the cygwin headers end up with sizeof(long) = 8. Thus cygwin+windows headers produce the wrong effective KIND for DWORD, and if the programmer says something like INTEGER, PARAMETER, PUBLIC :: DWORD = C_LONG, the result would be DWORD = 8 in 64-bit code.

BTW, gfortran looks like they are finally going to change the KIND of the internal LEN of CHARACTER variables to be C_PTRDIFF_T instead of the previous C_INT. I would have thought that C_SIZE_T (doesn't ifort use this?) were more appropriate.

 

0 Kudos
Highlighted

Ah, Cygwin C headers -

Jump to solution

Ah, Cygwin C headers - certainly if you're using gcc in Cygwin I could see (!) a problem there. Doesn't affect ifort. Yes, ifort uses C_SIZE_T for character lengths.

Retired 12/31/2016
0 Kudos