Using Windows API from gfortran

I’m wondering if anyone has a Windows API interface for gfortran? The Intel compiler provides a lot of these (ifwinty, kernel32, etc.) but I’m not aware of any publicly-available opensource library that has these. Does any exist? I see various posts of people writing ad hoc interfaces for these as needed, but what I think we need is a full library.

3 Likes

We should maintain such a library under fortran-lang.

What are some use cases of this that you need to access the Windows API directly, not via libc?

3 Likes

Yes, there are a lot of win APIs that can be useful (for example: run time loading of DLLs). The intel compiler on Windows comes with module interfaces for some of them so they are easy to call from ifort/ifx.

1 Like

I’ve been thinking for a while if, at least for dynamic libraries, stdlib wouldn’t be a good fit to hold a unique interface for loading libraries à la Numpy numpy/numpy/ctypeslib.py at v2.1.0 · numpy/numpy · GitHub. That way a single interface could be proposed to work in a cross-compiler/cross-os fashion.

2 Likes

If this is the feature you are after then rosetta code is a good place to start.
If this is of any interest to anyone I can provide you with a piece of code that implement dynamic loading. I use it all the time

To the best of my knowledge, the short answer to the OP question is NO, such library does not exists. And I spent countless hours looking for it.
The best strategy to be cross-platform would certainly to have a full POSIX interface but, Windows being Windows, it is not 100% POSIX compliant. Or rather it stopped at POSIX.1. That means that functionalities present in libs like dirent or pthread would require a Windows specific implementation. And so to get these features you will end up writing quite some C/C++.
If you dig into the source code of msys2 you will probably find all the code you need to simulate a POSIX api from the Windows api.
Personally I looked for lightweights alternatives:

Then, writing the Fortran interface was rather easy using existing projects link fortran-unix, M_system, fortran-posix or popen-fortran.

Of course, that’s not everything and you could also think of the api to spawn a process (Windows has popen but not fork and even popen shall be written _popen:rage:, see this PR for instance), open a named pipe (forget about mkfifo)…

And finally, I would always recommend writing some glue code in C/C++ and not calling the Windows api directly. This is especially true if you need to support both x86 and x64. Take a look at the simple sleep function. Win32 API routines on Windows x86 use the stdcall calling mechanism, which has a naming convention adding a @n at the end of the function name to signify the number of bytes to pop off the stack on return. That truly becomes nightmarish to code and maintain.

1 Like

Coincidentally, I was asked recently at work to generate “Enhanced Metafile” from my Windows Fortran program. These are image file almost never used, except in some Windows application, so in this precise situation, it’s not a problem if the code is OS-specific. Windows provides an API just to do this, so I was planning to write a Fortran binding to this wingdi.h package. I’ve looked a bit on the Internet, and I don’t think it exists. It would include functions to draw on screen too, which may be useful in other applications.

1 Like

There are plenty of situations where you actually need to call the Windows api directly.
Just look at the sleep function on stdlib. Another example is a function to get the full path from a relative path. A cross platform version could look like this:

#ifndef _WIN32
        function realpath_c(path, resolved_path) result(ptr) bind(C, name="realpath")
            import :: c_ptr, c_char
            character(kind=c_char, len=1), intent(in) :: path(*)
            character(kind=c_char, len=1), intent(out) :: resolved_path(*)
            type(c_ptr) :: ptr
        end function
#else
        function fullpath_c(resolved_path, path, maxLength) result(ptr) bind(C, name="_fullpath")
            import :: c_ptr, c_char, c_int
            character(kind=c_char, len=1), intent(out) :: resolved_path(*)
            character(kind=c_char, len=1), intent(in) :: path(*)
            integer(c_int), value, intent(in) :: maxLength
            type(c_ptr) :: ptr
        end function
#endif

    function fullpath(path) result(resolved_path)
        character(*), intent(in) :: path
        character(:), allocatable :: resolved_path
        !private
        type(c_ptr) :: ptr
        character(1) :: tmp(max_path)
        integer idx

        allocate (character(max_path) :: resolved_path)
#ifndef _WIN32
        ptr = realpath_c(path//c_null_char, tmp)
#else
        ptr = fullpath_c(tmp, path//c_null_char, max_path)
#endif
        resolved_path = transfer(tmp, resolved_path)
        idx = index(resolved_path, c_null_char)
        resolved_path = resolved_path(:idx - 1)
    end function

I do not know what you think about it but rather than having a Windows specific lib on Fortran-Lang, why not having a standard POSIX interface that would also work on Windows?

1 Like

Isn’t it what Cygwin provides ?

Indeed, but I was more thinking about the Fortran side of things :grin:.
As for Cygwin, it’s a big monolith available as binaries so I am not sure you can statically link to it. In addition, the license is not that permissive (LGPL) which might not be suitable for all cases.

I know, but what would be needed is then a C-Fortran interface to the posix routines, and it would work on Windows thanks to the Cygwin DLL (at least the part that the Cygwin DLL implements).

It’s not completely uncommon to have Windows applications that are ported from unix by embedding the Cygwin DLL and with minimal changes in the original code.

Well, the Fortran interface is the bare minimum. I had in mind a higher level layer much like what @jacobwilliams did for popen. It would go in the same direction as what is ongoing for linear algebra in stdlib.

1 Like

@davidpfister good points. I think it doesn’t even have to be POSIX, but if there is a platform independent functionality, then we can maintain it in stdlib. The problem with POSIX is that I think it sometimes goes too far and doesn’t always easily map natively on Windows. One can of course maintain an emulation layer like Cygwin, or msys2, or even git-bash style, but it feels weird and out-of-place. At the same time, one can absolutely maintain a large common subset and figure out API that feels native on all platforms.

2 Likes

Yeah, I see it as a much larger project to make a nice cross-platform library for this stuff.

In my case for now, I just want the Fortran interfaces to some of these api routines. I think it would be useful. I may try to get something like that started. One could later build a more Fortrannic library on top of that if they wanted, but the interfaces are really a separate thing.

Some of them likely don’t make much sense for other platforms though. AttachConsole might be one example.

1 Like

Which functions exactly are you looking at @jacobwilliams?
Something else to keep in mind: gfortran does not have the macro _WIN32 defined by default (unlike the intel compilers). That means that if you use fpm you need to add it in your toml and then your config is not cross platform anymore. There were discussions about supporting os specific directives in the toml but I am not aware about any development in that direction.

Indeed, AttachConsole looks kind of useless but GetConsoleMode and SetConsoleMode are required if you what your classic cmd to support ANSI formatting (which it does not by default)

One way to possibly accomplish that would be to (mostly) automatically parse the WinAPI documentation… the Microsoft documentation site really looks like it’s a GitHub deployment, so maybe doable?

Otherwise one can always look at the C header files, not sure how convoluted are them though as I’ve never used them.

Not ideal, but I normally wrap Windows API routines on an as-needed basis. There’s plenty of reasons to call the Windows API directly, usually to access the GUI or to use some of Windows’ more powerful features (threading features, high-level network calls, cryptography, pipes and process control).

You absolutely will run into issues with Windows API calls that are implemented as macros, which seem to be appearing more and more lately as older (but not deprecated or discontinued) API calls are superseded by more powerful calls. Microsoft is usually good about documenting these changes, but not always. Additionally, API calls involving strings in Windows normally have two variants, ANSI and Wide, so you’ll need make sure your interface calls the proper implementation (C macros make this seamless, of course). Once you start getting into the Win32 message loop, you’ll start bumping into some structures that are going to be highly unpleasant to wrap in Fortran.

Have you checked out the msys2 project, that has modified GCC tools to create native Windows applications?

My understanding is as follows: the modern Windows interface is known as UCRT, and is a Windows version of the C standard library. Other implementations of the C standard library are defined in the C standard and Posix, which is why there are some challenges with porting POSIX applications to native Windows).

You would need to write Fortran wrappers to call C-based UCRT functions, but that could be done.

there is also GitHub - microsoft/win32metadata: Tooling to generate metadata for Win32 APIs in the Windows SDK.

2 Likes