- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm not really experienced in Fortran, I tried unsuccessfully to call a Windows API function as a test (previously I tried some other tests such as locking the screen, with success).
The function is QueryProcessCycleTime (just for curiosity, it retrieves the cpu cycles count of a process, in my test code with a fixed pid of an actually existent process). Its syntax:
BOOL WINAPI QueryProcessCycleTime(
_In_ HANDLE ProcessHandle,
_Out_ PULONG64 CycleTime
);
I couldn't find the Fortran "translation" for these data types and I tried several combinations in my code (for each variables) with no luck. I compiled with
ifort /libs:static /exe: ... or
ifort /libs:qwin,static /exe: ...
but the output is always:
F 4936 0
(return value, pid, cycles count).
The function doesn't appear in the kernel32.f90 supplied by Intel (see Calling Windows API Routines for syntax not involving ISO_C_BINDING).
Going beyond the specific test I wondered if:
really Fortran can't load dlls supplying full path (without adding it as an environment variable)?
Or more in general and in a few words:
Can Fortran be used as a Win32 programming language?
(I don't mean only for a limited set of functions)
Or, at the end, is it (very, we know) useful only for number crunching?
My test code:
module process_cpu_cycles use ISO_C_BINDING implicit none public QueryProcessCycleTime interface function QueryProcessCycleTime(proc_id, cpu_cycles) bind(C,Name='QueryProcessCycleTime') use ISO_C_BINDING implicit NONE !DEC$ ATTRIBUTES STDCALL :: QueryProcessCycleTime logical(C_BOOL) :: QueryProcessCycleTime ! tried C_INT too integer(C_INTPTR_T), value :: proc_id ! tried without value integer(C_INTPTR_T), value :: cpu_cycles ! tried C_INT64_T too end function QueryProcessCycleTime end interface end module process_cpu_cycles program cycles use process_cpu_cycles use ISO_C_BINDING implicit none logical(C_BOOL) :: ret_val integer(C_INTPTR_T) :: pid integer(C_INTPTR_T) :: ccycle ! tried C_INT64_T too ccycle=0 pid=4936 ret_val = QueryProcessCycleTime(pid,ccycle) write (*,*) ret_val, pid, ccycle end program cycles
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You say, "I'm not really experienced in Fortran" - but can you state what you are experienced in? Is it C/C++? Because C/C++ is what Microsoft usually uses to give examples for the Windows API functions. But it is noticeable that Microsoft doesn't give anything for QueryProcessCycleTime and cyber world mostly shows links for C/C++ users having trouble using this function. Hence questions arise about your experience, what you're trying to do, the applicability of this particular API function for your needs, and what else you can use.
Note if overall CPU usage is what you're interested in, CPU_TIME standard intrinsic function in Fortran may perhaps serve your needs?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, Fortran can be used for a wide variety of Win32 programming. We do provide tens of thousands of API declarations, but Microsoft adds so many in each new Windows version it's hard to keep up. We have to create these manually.
Some Windows APIs are not usable except from C++. If it's usable from C, it's usable from Fortran.
I fixed up your code. The major error was the way you declared and used the ccid argument. You declared it as an address passed by value, but failed to use LOC() in the call. A minor error is using LOGICAL for the Bool datatype. You really should use the kind constants in IFWINTY rather than trying to map them into ISO_C_BINDING.
Here's a corrected version. Use whatever you need for pid.
module process_cpu_cycles implicit none public QueryProcessCycleTime interface function QueryProcessCycleTime(proc_id, cpu_cycles) bind(C,Name='QueryProcessCycleTime') use IFWINTY implicit NONE !DEC$ ATTRIBUTES STDCALL :: QueryProcessCycleTime integer(BOOL) :: QueryProcessCycleTime integer(HANDLE), value :: proc_id integer(ULONG64) :: cpu_cycles end function QueryProcessCycleTime end interface end module process_cpu_cycles program cycles use process_cpu_cycles use IFWINTY use KERNEL32, only: GetCurrentProcess implicit none integer(BOOL) :: ret_val integer(HANDLE) :: pid integer(LONG64) :: ccycle ! tried C_INT64_T too ccycle=0 pid=GetCurrentProcess() ret_val = QueryProcessCycleTime(pid,ccycle) write (*,*) ret_val, pid, ccycle end program cycles
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Oh, another error was that you thought the first argument was a process ID - it isn't. It's a process handle. If you have the process ID you get the handle with OpenProcess - see https://msdn.microsoft.com/en-us/library/windows/desktop/ms684868(v=vs.85).aspx
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
When translating those API interfaces to good Fortran, you will find
https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
to be very helpful. A couple of other hints:
- Always copy the dummy argument names verbatim from the MSDN documentation. This is especially helpful for functions with long argument lists, where it is desirable to make a keyword call. If your argument names match the MSDN docs, you won't have to look in more than one place to know what each argument is supposed to be.
- C has no LOGICAL type. LOGICAL(C_BOOL) actually corresponds to C99 _Bool, which is by the C standard an integer type. The companion processor to ifort for Windows, MSVC++, doesn't support C99, so LOGICAL(C_BOOL) doesn't actually match any C data type.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Steve, anyway it didn't work (same output). I didn't understand IFWNTY can be used just as ISO_C_BINDING. The example in the guide looked a bit different.
Yes, I noticed it was an handle but I was set on the wrong track by wmic path win32_process which is reporting pid and handle as the same. I had that in mind.
I attempted first with C_INT instead of C_BOOL: same result, no errors, no warnings.
Yes, Reapeat Offender, I already downloaded that list. But, at the end, I shouldn't say it is so helpful since it differs greatly with respect to the Fortran equivalent supplied for binding.
I'm trying to undertand if I can adopt Fortran (and consequently organize myself) even in the (frequent) cases I need to call Windows functions. Frankly, to me, it remains hard to understand if the issues in the test above are exceptional or standard. And I couldn't understand if one could code his own wrappers in case of need (for specific functions, for example). In other words, how flexible this interoperability is.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The code I posted does work - I tried it. You had a couple of usage errors and a misunderstanding of the first argument. You can't pass in a process ID - you have to get a handle to the desired process (which your privileges may or may not allow.)
APIs added after Windows XP may or may not be there. We fill them in when we can. This one was new in Vista.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Repeat Offender wrote:
- C has no LOGICAL type. LOGICAL(C_BOOL) actually corresponds to C99 _Bool, which is by the C standard an integer type. The companion processor to ifort for Windows, MSVC++, doesn't support C99, so LOGICAL(C_BOOL) doesn't actually match any C data type.
According to MSDN, all versions of Visual Studio which are still under support have bool as a built-in type (maybe not _Bool). It does seem to differ marginally from standards.
VS2015 supports a fair amount of c99, an obvious exception being VLA (counterpart of Fortran automatic array), which was made optional in c11.
I'm not sure, where there are conflicts in usage between MSVC++ and ICL, which one counts as the companion processor to ifort.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The code I posted does work - I tried it. You had a couple of usage errors and a misunderstanding of the first argument. You can't pass in a process ID - you have to get a handle to the desired process (which your privileges may or may not allow.)
Ok at the first step I failed manipulating the code. If leaved unmodified "maybe" it works. It gives -1 (the pseudo handle) as return value. From MSDN for GetCurrentProcess: "A pseudo handle is a special constant, currently (HANDLE)-1, that is interpreted as the current process handle.". So I can't understand if everything was going as expected... Anyway the return value (1) for QueryProcessCycleTime
shows that it succededed and the cycles count has a reliable aspect.
Maybe this was an example a bit hostile. I admit, I never heard about the process handle before, and it seems to be not so well known. I couldn't find a way to get the handles for non-current-processes in a reasonable amount of time (maybe going deeply in other APIs, but that was only a test, after all...). I suspect that this handle thing can be the cause for having troubles with the QueryProcessCycleTime
function.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I gave you a link to the MSDN page that explains how to get process handles.
I wish I had an automated way of creating new interface blocks from the MSDN description. I did try working on one a while ago but gave it up. Otherwise it's an intensely manual process.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I beg your pardon, Steve, I didn't realize immediately that it was THE hint. I searched elsewhere.
The following code is perfectly running on my machine:
module process_cpu_cycles implicit none public QueryProcessCycleTime interface function QueryProcessCycleTime(proc_id, cpu_cycles) bind(C,Name='QueryProcessCycleTime') use IFWINTY implicit NONE !DEC$ ATTRIBUTES STDCALL :: QueryProcessCycleTime integer(BOOL) :: QueryProcessCycleTime integer(HANDLE), value :: proc_id integer(ULONG64) :: cpu_cycles end function QueryProcessCycleTime end interface end module process_cpu_cycles program cycles use process_cpu_cycles use IFWINTY use KERNEL32, only: GetCurrentProcess, OpenProcess implicit none integer(BOOL) :: ret_val integer(LONG64) :: ccycle integer(HANDLE) :: proc_handle integer(DWORD) :: dwDesiredAccess integer(BOOL) :: bInheritHandle integer(DWORD) :: dwProcessId dwDesiredAccess=10000 bInheritHandle=0 dwProcessId=4936 ! PID of an existent process proc_handle=OpenProcess(dwDesiredAccess,bInheritHandle,dwProcessId) ccycle=0 ret_val = QueryProcessCycleTime(proc_handle,ccycle) write (*,*) ret_val, proc_handle, ccycle end program cycles
The value for dwDesiredAccess is sufficiently high for the scope. The PID (dwProcessId) is of an existent process. bInheritHandle can be 0 or 1 in this case.
I could confirm the correctness of the result (the cpu cycles count for the process) comparing it with other (few) softwares that retrieve this value.
I'm quite impressed. This function is not present in the include directory but it can work anyway? Have we suddenly jumped on the other side, Fortran can beat C/C++??
Thanks Steve, these kind of results can be a good news (for me, at least).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Steve
Just joined the forum.I am basically a structural engineer using fortran for the past two decades.
My present issue is using Fortran dlls from vb.net.
A simple and concise example would be very helpful.
Thanking you in advance,
Regards
Ambaprasad P
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
p p - Pretty much anything C can do, Fortran can do. If a particular API routine or definition is not in the compiler's modules, you can always define your own. We will be filling these in over time.
Ambaprasad, there are two examples provided of VB calling Fortran DLLs in the MixedLanguage ZIP under Samples, installed along with the compiler.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A suggestion - if you find you have to add your own declaration of a Windows API item because it isn't in our provided modules, change the name so that it won't create a conflict when we do add the entry. For example, put an X at the end of the function name (not in the Name= value, of course!)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was trying to call the Windows API function NtQuerySystemTime, which is in ntdll.dll (it retrieves the current system time), but linking failed: LNK1120, unresolved symbol.
No ntdll-like thing was present in my Fortran installation.
So I tried to load ntdll.dll using the Windows API functions LoadLibrary and GetProcAddress and this way it worked. I was able to successfully access the NtQuerySystemTime function.
Note that with LoadLibrary you have the possibility (but it's not mandatory) to load a module providing the full path.
Here is the ISO_C_BINDING version of the code. IFWINTY has been called only to avoid rewriting the type for T_FILETIME.
program getSystemTime use ISO_C_BINDING use IFWINTY implicit none interface function LoadLibrary(lpFileName) bind(C,name='LoadLibraryA') ! the ansi version use ISO_C_BINDING implicit none character(C_CHAR) :: lpFileName(*) !DEC$ ATTRIBUTES STDCALL :: LoadLibrary INTEGER(C_INTPTR_T) :: LoadLibrary end function LoadLibrary function GetProcAddress(hModule, lpProcName) bind(C, name='GetProcAddress') use ISO_C_BINDING implicit none !DEC$ ATTRIBUTES STDCALL :: GetProcAddress TYPE(C_FUNPTR) :: GetProcAddress INTEGER(C_INTPTR_T), value :: hModule character(C_CHAR) :: lpProcName(*) end function GetProcAddress end interface abstract interface subroutine gettime(SystemTime) bind(C) use IFWINTY TYPE (T_FILETIME) SystemTime end subroutine end interface character*(260) lpLibFileName character*(260) lpProcName TYPE (T_FILETIME) SystemTime INTEGER(C_INTPTR_T) :: module_handle TYPE(C_FUNPTR) :: module_address PROCEDURE(gettime), POINTER :: fort_addr lpLibFileName="C:\Windows\system32\ntdll.dll" ! "ntdll.dll" is good anyway lpProcName="NtQuerySystemTime" // achar(0) module_handle=LoadLibrary(lpLibFileName) module_address=GetProcAddress(module_handle,lpProcName) call C_F_PROCPOINTER(module_address, fort_addr) call fort_addr(SystemTime) write (*,*) trim(lpLibFileName) ! loaded module name write (*,*) module_handle ! module handle write (*,*) SystemTime ! the two parts of system time end program getSystemTime
I'm not familiar with the abstract interface. I guess it allows building an interface without an explicit reference to the function, which would lead to a linking error.
Now the IFWINTY version. Use of IFWINTY and KERNEL32 provide already the necessary interfaces for LoadLibrary and GetProcAddress.
ISO_C_BINDING is loaded too, but this time for a less aesthetic reason. I didn't know how to translate the C_F_PROCPOINTER subroutine in a IFWINTY way. So it was necessary to make use of transfer to cast module_address to a variable with the suitable data type for C_F_PROCPOINTER.
This mixing between wrappers looks a bit messy, though.
program getSystemTime use IFWINTY use KERNEL32, only: LoadLibrary, GetProcAddress use ISO_C_BINDING implicit none abstract interface subroutine gettime(SystemTime) bind(C) use IFWINTY TYPE (T_FILETIME) SystemTime end subroutine end interface character*(260) lpLibFileName character*(260) lpProcName TYPE (T_FILETIME) SystemTime integer(HANDLE) :: module_handle integer(LPVOID) :: module_address TYPE(c_funptr) :: module_address2 PROCEDURE(gettime), POINTER :: fort_addr lpLibFileName="C:\Windows\system32\ntdll.dll" ! "ntdll.dll" is good anyway lpProcName="NtQuerySystemTime"// achar(0) module_handle=LoadLibrary(lpLibFileName) module_address=GetProcAddress(module_handle,lpProcName) module_address2=transfer(module_address,module_address2) call C_F_PROCPOINTER(module_address2, fort_addr) call fort_addr(SystemTime) write (*,*) trim(lpLibFileName) ! loaded module name write (*,*) module_handle ! module handle write (*,*) SystemTime ! the two parts of system time end program getSystemTime
In both cases, command line: ifort source.f90 /libs:static /exe:program.exe
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
ntdll is a core Windows DLL, not a Windows API library. We don't provide interfaces to things that aren't in import libraries. Besides, MSDN says not to use NtQuerySystemTime and to use GetSystemTimeAsFileTime instead.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It's possible to get or make your own ntdll.lib: see http://stackoverflow.com/questions/6774967/lnk2019-unresolved-external-symbol-ntopenfile . It looks like you're getting the hang of interfacing with Windows API functions. I do see one mistake: NtQuerySystemTime is declared with the WINAPI macro in MSDN's documentation, which indicates the STDCALL calling convention. Thus you need
!DEC$ ATTRIBUTES STDCALL :: gettime
in the declaration. BTW, I think you should call the interface NtQuerySystemTime or at worst NtQuerySystemTimeX instead of gettime, it's more self-documenting that way. Why are you typing its argument as T_FILETIME when the MSDN docs document it as T_LARGE_INTEGER? INTEGER(INT64) (INT64 coming from ISO_FORTRAN_ENV) would be fine, too. Also lpLibFileName needs a terminating NUL which you forgot.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
p p. wrote:
.. Here is the ISO_C_BINDING version of the code. IFWINTY has been called ..
Not sure what you're getting at, what you suggest is neither here nor there. Almost all the Intel Fortran users would simply prefer to make use of MSDN-recommended function of GetSystemTimeAsFileTime instead and they would do so very simply as:
program getSystemTime use IFWINTY, only : T_FILETIME use KERNEL32, only : GetSystemTimeAsFileTime implicit none type(T_FILETIME) :: SystemTime call GetSystemTimeAsFileTime(SystemTime) write (*,*) SystemTime stop end program getSystemTime
and those need portable code would go the full distance with standard features for interoperability with C via ISO_C_BINDING and have no references to Intel Fortran provided modules of IFWINTY and KERNEL32 at all.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Premising: the codes above were perfectly linking and running, on my machine at least.
ntdll is a core Windows DLL, not a Windows API library. We don't provide interfaces to things that aren't in import libraries
For what are my needs, I don't mind subdividing things in objects those times it's not significant. There was a function, there, in the Windows world and I could call it coding in Fortran. That's the point.
MSDN says not to use NtQuerySystemTime and to use GetSystemTimeAsFileTime instead
Yes, I saw it. It was good for testing purpose, in other cases may not (or yes anyway).
NtQuerySystemTime is declared with the WINAPI macro in MSDN's documentation, which indicates the STDCALL calling convention. Thus you need !DEC$ ATTRIBUTES STDCALL :: gettime
in the declaration. BTW, I think you should call the interface NtQuerySystemTime or at worst NtQuerySystemTimeX instead of gettime, it's more self-documenting that way
I don't know if I'm missing something. Anyway, this is what I did:
I called with compiler directives (!DEC$) ONLY the LoadLibrary and the GetProcAddress functions. In other words I used the Fortran built-in module loader to call a Windows module loader. Then again I used the Windows module loader (so, in some sense, outside the Fortran world) to load ntdll.dll and make its exported functions accessible. It seemed to be necessary to provide an abstract interface block, but I can't say more than this about this specific subject.
So, I had to do this way beacuse I wasn't able to achieve this result only using !DEC$ directives (in other words: only using the Fortran/ifort built-in module loader). In fact, the result was: unresolved symbol.
Also lpLibFileName needs a terminating NUL which you forgot.
It worked anyway, and me too I asked myself why. However I had to add //achar(0) in that specific point to make it work. Possibly I omitted the null termination in other working code (always testing).
It's possible to get or make your own ntdll.lib
I was thinking to test this way too.
Why are you typing its argument as T_FILETIME when the MSDN docs document it as T_LARGE_INTEGER? INTEGER(INT64)
For what I can understand, this is the (ready to use) IFWINTY translation for those Windows data types. I used it in the ISO_C_BINDING version of the code too, avoiding to translate it in a ISO_C_BINDING "language".
Almost all the Intel Fortran users would simply prefer...
In fact I'm trying to go beyond what generally Fortran users do.
and those need portable code would go the full distance with standard features for interoperability with C via ISO_C_BINDING and have no references to Intel Fortran provided modules of IFWINTY and KERNEL32 at all
I'm going step by step. I agree with you for not to have references to Intel-only modules, if this could be possible.
Lastly I want to point out, once again, that with the LoadLibrary you can load a module with his full (or relative) path. I don't know if I missed something, but I couldn't find I way to do the same with only !DEC$ directives.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This mixing between wrappers looks a bit messy, though.
It makes more sense and look cleaner to create your own interfaces module e.g. MyWinty to compliment IFWIN/IFWINTY and just add USE MyWinty where appropriate. Or to go further add IFWIN to MyWinty and only use that!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
app4619 wrote:
This mixing between wrappers looks a bit messy, though.
It makes more sense and look cleaner to create your own interfaces module e.g. MyWinty to compliment IFWIN/IFWINTY and just add USE MyWinty where appropriate. Or to go further add IFWIN to MyWinty and only use that!
In fact. Anyway, if we consider the tools made available as standard (I'm considering IFWINTY standard, which it isn't) it seems that this mixing could arise quite easily. The code above, involving a simple call to the NtQuerySystemTime function, is simple enough to be written solely for the ISO_C_BINDING wrapper (I guess so). But... is it always so? From a more general perspective, I mean, not only case by case.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page