Although GetCurrentDirectory works fine, GetModuleFileName does not;
and I suspect
the reason to lie in the first parameter, for which Windows expects a
4-byte unsigned integer
value of zero or null. How should I pass this unsigned zero ??
I have the same problem tying to use the Windows Sleep function, which
expects
Milliseconds, an unsigned doubleword.
I'd be very grateful to hear of any way to accomplish this from within
Gfortran (ie, not by writing my own C function).
Mark Horridge
!--------------------------------------------------------------
module Win32
use ISO_C_BINDING
implicit none
private
public GetCurrentDirectory
interface
function GetCurrentDirectory(cchBuffer, lpszCurDir)
bind(C,Name='GetCurrentDirectoryA')
use ISO_C_BINDING
implicit NONE
!GCC$ ATTRIBUTES STDCALL :: GetCurrentDirectory
integer(C_LONG) GetCurrentDirectory
integer(C_LONG) cchBuffer
character(kind=C_CHAR) lpszCurDir
end function GetCurrentDirectory
end interface
public GetModuleFileName
interface
function GetModuleFileName(hmod, lpszfnam, cchBuffer)
bind(C,Name='GetModuleFileNameA')
use ISO_C_BINDING
implicit NONE
!GCC$ ATTRIBUTES STDCALL :: GetModuleFileName
integer(C_LONG) GetModuleFileName
integer(C_LONG) hmod
character(kind=C_CHAR) lpszfnam
integer(C_LONG) cchBuffer
end function GetModuleFileName
end interface
end module Win32
program test
use Win32
use ISO_C_BINDING
implicit none
integer(C_LONG) b
character StringA*(255)
b = GetCurrentDirectory(255,StringA)
print *,' Current Dir: '//StringA(1:b)
b = GetModuleFileName(0,StringA,255)
print *,b
print *,' Current ExeName: '//StringA(1:b)
end program test
--
Tim Prince
>I am attempting, using 32-bit gfortran in Windows, to call some
> Windows API functions. I am having some success, and can for instance
> report the current directory. I am using the current mingw binaries,
> based on gcc version 4.5.0 (GCC). I compile the program below via:
> gfortran -mrtd test4.f90 -otest4.exe
> It compiles fine, without warnings.
> When I run it, the output is:
> Current Dir: C:\temp
> 0
> Current ExeName:
> Although GetCurrentDirectory works fine, GetModuleFileName does not;
> and I suspect
> the reason to lie in the first parameter, for which Windows expects a
> 4-byte unsigned integer
> value of zero or null. How should I pass this unsigned zero ??
> I have the same problem tying to use the Windows Sleep function, which
> expects
> Milliseconds, an unsigned doubleword.
> I'd be very grateful to hear of any way to accomplish this from within
> Gfortran (ie, not by writing my own C function).
> !--------------------------------------------------------------
> end module Win32
First off, just forget about -mrtd with gfortran. It doesn't work
in any way you might consider sensible. Those !GCC$ ATTRIBUTES STDCALL
Directive Enhanced Compilation statements you put in there do the
right thing already.
Second, if you can, try to make interfacing to Win32 API functions
work in 64-bit Windows then go back and see if what you did works
in 32-bit Windows. 64-bit Windows is so much easier because there
is no issue with STDCALL: there is only one calling convention.
Third, look up the documention for the function you are trying to
interface to in MSDN. Use exactly the names given there; don't
try to be creative or abbreviate or anything. This doesn't have
any effect on whether or not your program works, it just makes
it more self-documenting. But you do have a real problem in
writing the interfaces. The integer arguments are passed by value
according to MSDN, so they should read, for example:
integer(C_LONG), value :: nBufferLength
Also HMODULE is a handle according to MSDN, and handles are
integer(C_INTPTR_T), not integer(C_LONG). Doesn't make a
difference in 32-bit Windows, I know, but if you make the change
as suggested your program will work perfectly in 32-bit gfortran,
64-bit gfortran, and 64-bit ifort. Sorry about 32-bit ifort, Intel
chose to make interfacing to STDCALL procedures not work with
ISO_C_BINDING.
And your string arguments should specify that you are passing
arrays, not single characters by reference. Maybe the way you
are doing works in the compilers you use now, the I dont think
that that is just an accident of implementation, not anything
the standard says.
So fixing just your interface bodies and getting rid of -mrtd, I
get:
C:\gfortran\clf\wintest>type wintest.f90
module Win32
use ISO_C_BINDING
implicit none
private
public GetCurrentDirectory
interface
function GetCurrentDirectory(nBufferLength, lpBuffer) &
bind(C,Name='GetCurrentDirectoryA')
use ISO_C_BINDING
implicit NONE
!GCC$ ATTRIBUTES STDCALL :: GetCurrentDirectory
integer(C_LONG) GetCurrentDirectory
integer(C_LONG),value :: nBufferLength
character(kind=C_CHAR) lpBuffer(*)
end function GetCurrentDirectory
end interface
public GetModuleFileName
interface
function GetModuleFileName(hModule, lpFileName, nSize) &
bind(C,Name='GetModuleFileNameA')
use ISO_C_BINDING
implicit NONE
!GCC$ ATTRIBUTES STDCALL :: GetModuleFileName
integer(C_LONG) GetModuleFileName
integer(C_INTPTR_T), value :: hModule
character(kind=C_CHAR) lpFileName(*)
integer(C_LONG), value :: nSize
end function GetModuleFileName
end interface
end module Win32
program test
use Win32
use ISO_C_BINDING
implicit none
integer(C_LONG) b
character StringA*(255)
b = GetCurrentDirectory(len(StringA),StringA)
print *,' Current Dir: '//StringA(1:b)
b = GetModuleFileName(0_C_INTPTR_T,StringA,len(StringA))
print *,b
print *,' Current ExeName: '//StringA(1:b)
end program test
C:\gfortran\clf\wintest>gfortran wintest.f90 -owintest
C:\gfortran\clf\wintest>wintest
Current Dir: C:\gfortran\clf\wintest
35
Current ExeName: C:\gfortran\clf\wintest\wintest.exe
C:\gfortran\clf\wintest>type wintest.f90
module Win32
use ISO_C_BINDING
implicit none
private
public GetCurrentDirectory
interface
function GetCurrentDirectory(nBufferLength, lpBuffer) &
bind(C,Name='GetCurrentDirectoryA')
use ISO_C_BINDING
implicit NONE
!GCC$ ATTRIBUTES STDCALL :: GetCurrentDirectory
integer(C_LONG) GetCurrentDirectory
integer(C_LONG),value :: nBufferLength
character(kind=C_CHAR) lpBuffer(*)
end function GetCurrentDirectory
end interface
public GetModuleFileName
interface
function GetModuleFileName(hModule, lpFileName, nSize) &
bind(C,Name='GetModuleFileNameA')
use ISO_C_BINDING
implicit NONE
!GCC$ ATTRIBUTES STDCALL :: GetModuleFileName
integer(C_LONG) GetModuleFileName
integer(C_INTPTR_T), value :: hModule
character(kind=C_CHAR) lpFileName(*)
integer(C_LONG), value :: nSize
end function GetModuleFileName
end interface
end module Win32
program test
use Win32
use ISO_C_BINDING
implicit none
integer(C_LONG) b
character StringA*(255)
b = GetCurrentDirectory(len(StringA),StringA)
print *,' Current Dir: '//StringA(1:b)
b = GetModuleFileName(0_C_INTPTR_T,StringA,len(StringA))
print *,b
print *,' Current ExeName: '//StringA(1:b)
end program test
C:\gfortran\clf\wintest>gfortran wintest.f90 -owintest
C:\gfortran\clf\wintest>wintest
Current Dir: C:\gfortran\clf\wintest
35
Current ExeName: C:\gfortran\clf\wintest\wintest.exe
I wish you similar success.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
We have managed to extend your example to encompass
GlobalMemoryStatus, GetVersionEx, GetWindowsDirectory,
GetCurrentDirectory GetModuleFileName Sleep GetSystemInfo
GetFileAttributes GetCommandLine GetFullPathName and GetLastError
to create 32 and 64-bit exe files which run OK. That program is at:
http://www.monash.edu.au/policy/ftp/gpextra/test9.f90
It gives a compiler warning, and is doubtless sub-optimal -- but gives
a basis to progress further.
CreateProcess may be our next goal.
Thank you again,
Mark Horridge
> We have managed to extend your example to encompass
> GlobalMemoryStatus, GetVersionEx, GetWindowsDirectory,
> GetCurrentDirectory GetModuleFileName Sleep GetSystemInfo
> GetFileAttributes GetCommandLine GetFullPathName and GetLastError
> to create 32 and 64-bit exe files which run OK. That program is at:
> http://www.monash.edu.au/policy/ftp/gpextra/test9.f90
> It gives a compiler warning, and is doubtless sub-optimal -- but gives
> a basis to progress further.
> CreateProcess may be our next goal.
There are a few things I would have changed in your example, but I
haven't gone over the whole thing. You can get rid of the warning
by changing:
character(128) szCSDVersion
to one of:
character(kind=C_CHAR) szCSDVersion*128
character(len=128,kind=C_CHAR) szCSDVersion
character(128,C_CHAR) szCSDVersion