- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You'll probably also want to read Using Intel® Visual Fortran to Create and Build Windows*-Based Applications
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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-9781555582494.aspx
Mine cost US$31 including shipping. Better Wortd also donate a book to charity for each one you buy.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page