- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The following interface works when the function I am calling is in a C DLL built with a cdecl calling convention. What do I change if the DLL is replaced with one having a stdcall convention?
function TA_GetFeatureValue(handle, featureName, lpValueStr, cchValue) bind(c, name = 'TA_GetFeatureValue') result(retval)
import
integer(c_int32_t), value :: handle ! Note that Fortran doesn't have unsigned integer types
integer(c_short), dimension(*) :: featureName
integer(c_short), dimension(*) :: lpValueStr
integer(c_int), value :: cchValue ! Note the value attribute here
integer(c_long) :: retval
end function
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you're on Windows OS and the DLL and the application are built for 64-bit platform (e.g., x64 configuration in Visual Studio), then 'stdcall' should make no difference and you should not require any changes.
However, if the target platform is 32-bit (e.g., x86 configuration in Visual Studio for the C DLL, etc.), then you can try including the !DIR$ ATTRIBUTES for STDCALL - see this link.
function TA_GetFeatureValue(handle, featureName, lpValueStr, cchValue) bind(c, name = 'TA_GetFeatureValue') result(retval)
!dir$ attributes stdcall :: TA_GetFeatureValue
..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FortranFan's suggestion of adding an ATTRIBUTES STDCALL directive is indeed the correct approach. Earlier versions of Intel Fortran did not allow this with BIND(C), but that was fixed several versions ago.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm close, but not quite there. I replaced the cdecl DLL with the stdcall, and tried running the program (a console program), and it worked! But at END PROGRAM throws an exception about the stack. No surprise there.
I added the ATTRIBUTES STDCALL statements and the program would not link, with errors like the following.
unresolved external symbol _TA_GetFeatureValue@16 referenced in function _MAIN__
I tried adding an underscore in front of the routine name like this:
!dir$ attributes stdcall :: _TA_GetFeatureValue
The program would build and run, but at exit throws the same exception about the stack.
I tried adding an alias statement such as the following, but the compiler said The BIND(C) attribute for this symbol conflicts with a DEC$ ATTRIBUTES ALIAS
!DEC$ ATTRIBUTES ALIAS:"TA_GetFeatureValue" :: TA_GetFeatureValue
What am I missing?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
First thing to do here is determine the actual global name of the routine. Take the .lib from the DLL build and do:
dumpbin -exports mydll.lib
You should not need to add the leading underscore - BIND(C) will do that for you.
When you added the underscore to the ATTRIBUTES directive, you effectively removed the directive as you're now changing the attribute of a different routine.
It's possible that the new DLL isn't following the C compiler's conventions for routine naming - evidence being that you can link without it. If that is the case, you can't use BIND(C) and must revert to the older way of:
!DIR$ ATTRIBUTES STDCALL,REFERENCE,ALIAS:"_TA_GetFeatureValue" :: TA_GetFeatureValue
You will also need to add a !DIR$ ATTRIBUTES VALUE :: cchValue to the interface block.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, Steve. That did the trick. There are of course other routines, and once I gave all necessary variables the VALUE attribute, it works great.
I've attached a dumpbin. It shows only two lines containing GetFeatureValue.
15 E 00023464 GetFeatureValue
36 23 00023272 TA_GetFeatureValue
In Dependency Walker I see these two along with a third; _TAGetFeatureValue@16. Does this mean the DLL isn't following the C compiler's conventions for routine naming?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Now I'm confused. You earlier reported an error:
unresolved external symbol _TA_GetFeatureValue@16 referenced in function _MAIN__
yet that exact symbol is in the export library:
87 56 00023272 _TA_GetFeatureValue@16
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It's a mystery to me, too.
It may not be important, but I mis-stated what was in the dumpbin. I should have said:
15 E 00023464 GetFeatureValue
36 23 00023272 TA_GetFeatureValue
66 41 00023464 _GetFeatureValue@12
87 56 00023272 _TA_GetFeatureValue@16
What I now have for a typical interface block is as follows.
function TA_GetFeatureValue(handle, featureName, lpValueStr, cchValue) result(retval)
!DIR$ ATTRIBUTES STDCALL,REFERENCE,ALIAS:"_TA_GetFeatureValue" :: TA_GetFeatureValue
!DIR$ ATTRIBUTES VALUE :: handle, cchValue
import
integer(c_int32_t), value :: handle
integer(c_short), dimension(*) :: featureName
integer(c_short), dimension(*) :: lpValueStr
integer(c_int), value :: cchValue ! Note the value attribute here
integer(c_long) :: retval ! HRESULT is typedef long
end function
So far it works. Is this the right way?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I would be more comfortable if you tacked on the @16 to the ALIAS, but then it should have worked before with just the STDCALL directive and BIND(C).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have been using BIND(C) to access COMMON blocks in C++ in an x86 program. I had never needed to include the STDCALL stuff. Was I lucky? or this is a different situation?
I. Konuk
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Different. STDCALL affects procedure calls on 32-bit only. It has to do with who pops the argument list off the stack. With STDCALL, the called routine does it in the RET instruction; with C, the caller does it. This is why you get stack corruption if you mix them.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve - do you have any ideas why the STDCALL directive was not adequate? Could it have something to do with the 4 different flavors of the routine identified by the dumpbin? Should I report back to the developer of this DLL that there is something odd with it?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If I may be brutally honest, I don't believe you tested the STDCALL directive correctly. The evidence from the dump of the exports shows that the symbol you reported as missing is actually there. Perhaps you linked to the wrong library - I don't know. That there is something "odd with the DLL" would be far down my list.
If you can attach a ZIP of a reproducible test case (Fortran source and export LIB - don't need the DLL), I'd be happy to take a look.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Being honest is not brutal.
As I reported earlier, the following gives me unresolved external linker error.
!DIR$ ATTRIBUTES STDCALL :: TA_GetFeatureValue
Whereas the following gets rid of the linker error, but when the program finishes running I got an error about corrupting the stack. But Steve said earlier an underscore should not be required because BIND C should do that.
!DIR$ ATTRIBUTES STDCALL :: _TA_GetFeatureValue
Anyhow, today I'm not getting the error about the stack, but I still need to add the underscore.
In the attached zip, open LimeMod stdcall.f90 and go to line 46. If the underscore is removed, I get unresolved external. With the underscore, the code builds and runs, but strangely doesn't corrupt the stack like it did for me a few days ago.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, I see we have a misunderstanding here. It doesn't help that the compiler isn't alerting you about it.
You have:
function TA_GetFeatureValue(handle, featureName, lpValueStr, cchValue) result(retval) bind(c, name = 'TA_GetFeatureValue')
!DIR$ ATTRIBUTES STDCALL :: _TA_GetFeatureValue
What you did here was tell the compiler that a routine named _TA_GetFeatureValue is STDCALL. Great, except that's not the name of the routine you're declaring an interface to. The result is that this directive is silently ignored.
I constructed a minimal example to demonstrate this. Here's the result of building with the directive the way you had it:
test.obj : error LNK2019: unresolved external symbol _TA_GetFeatureValue referenced in function _MAIN__
test.exe : fatal error LNK1120: 1 unresolved externals
(not linking to a library)
and here's with the underscore in the directive removed:
test.obj : error LNK2019: unresolved external symbol _TA_GetFeatureValue@16 referenced in function _MAIN__
test.exe : fatal error LNK1120: 1 unresolved externals
Note that in both cases the compiler added the leading underscore, and with the correct name in the directive also added the @16 for STDCALL.
Another thing I see in the dumpbin output is that the C++ compiler (I think that's what built the library) has both _TA_GetFeatureValue and _TA_GetFeatureValue@16 aliased to the same entry point. So it should not matter which of these you call - as long as the caller knows to apply the STDCALL mechanism. When you incorrectly add the leading underscore to the procedure name in the directive, the compiler thinks it is using the C mechanism and the stack gets corrupted by popping an extra 16 bytes from the stack.
The insidious thing about stack corruption is that it isn't always immediately obvious - it all depends on what happens after that.
Now I am going to link my test program to your library (with the errant underscore removed.) Let's see what I get:
test.obj : error LNK2019: unresolved external symbol _TA_GetFeatureValue@16 referenced in function _MAIN__
So that's what you see. Fine. Now let's look at the dumpbin.txt you included:
Dump of file turboactivate.DLL
File Type: DLL
Section contains the following exports for TurboActivate.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
106 number of functions
106 number of names
...
87 56 00023272 _TA_GetFeatureValue@16
Looks reasonable. But wait.. it's a dump of the DLL, not the .LIB. What do we get if we dump the .LIB? It's short so I'll include the whole thing:
Dump of file turboactivate.lib
File Type: LIBRARY
Exports
ordinal name
?DeleteProductKey@@YAXI@Z (void __cdecl DeleteProductKey(unsigned int))
?GetPPDetails@@YAJPAUPartialProductDetails@@@Z (long __cdecl GetPPDetails(struct PartialProductDetails *))
?SetProgressDelegate@@YAXP6AXH@Z@Z (void __cdecl SetProgressDelegate(void (__cdecl*)(int)))
_Activate
_ActivateEx
_ActivateFromFile
_ActivationRequestToFile
_ActivationRequestToFileEx
_CheckAndSavePKey
_Deactivate
_DeactivationRequestToFile
_ExtendTrial
_GetCurrentProduct
_GetExtraData
_GetFeatureValue
_GetPKey
_IsActivated
_IsDateValid
_IsGenuine
_IsGenuineEx
_IsProductKeyValid
_PDetsFromPath
_SetCurrentProduct
_SetCustomActDataPath
_SetCustomProxy
_TA_Activate
_TA_ActivateFromFile
_TA_ActivationRequestToFile
_TA_CheckAndSavePKey
_TA_Cleanup
_TA_Deactivate
_TA_DeactivationRequestToFile
_TA_ExtendTrial
_TA_GenuineDays
_TA_GetExtraData
_TA_GetFeatureValue
_TA_GetHandle
_TA_GetPKey
_TA_GetVersion
_TA_IsActivated
_TA_IsDateValid
_TA_IsGenuine
_TA_IsGenuineEx
_TA_IsProductKeyValid
_TA_PDetsFromByteArray
_TA_PDetsFromPath
_TA_SetCustomActDataPath
_TA_SetCustomProxy
_TA_SetTrialCallback
_TA_TrialDaysRemaining
_TA_UseTrial
_TA_UseTrialVerifiedFromFile
_TA_UseTrialVerifiedRequest
_TrialDaysRemaining
_UseTrial
What's missing? My guess is that this is a 64-bit .LIB, naturally missing all of the STDCALL entry points. Because the DLL itself is 32-bit, you would not notice the mismatch on running.
The solution is to 1) not put a leading underscore on the procedure name in the directive and 2) link against the correct export library.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What you did here was tell the compiler that a routine named _TA_GetFeatureValue is STDCALL. Great, except that's not the name of the outine you're declaring an interface to. The result is that this directive is silently ignored.
Hmmm not very user friendly. It begs the question why the STDCALL needs a name at all when in a bind(c name= is specified. In gfortran the stdcall decl is specified for the actual Fortran name rather the the alias which also makes more sense.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm not being clear here, it seems.
The STDCALL directive applies to the Fortran procedure name, NOT the alias. You are changing an attribute of the name as referenced in your Fortran code. This should be the same as gfortran.
When you use BIND(C, NAME=), the standard says that any "decoration" of the name should match what the "companion C processor" would do. And it does - MSVC adds the leading underscore and the @16 suffix when you tell it that a function is __stdcall.
You need the STDCALL in Fortran because this affects the generated code. The default (for both ifort and MSVC) is the "C" mechanism, where the caller pops the stack after return. STDCALL has the called procedure do the popping, but this then means that the called procedure has to know exactly how many bytes to pop. To help avoid mismatches, the convention is to append @n to the procedure name, where n is the number of bytes.
What you are seeing is that MSVC is ALSO emitting a name without the suffix - and Intel Fortran does this too. Why? Fortran does it because that allows you to declare a name simply EXTERNAL and pass it as an argument. I am not sure why MSVC is doing it as well.
I forgot to note that you made the same error with the directive for several other procedures you declared in this source.
As for why the compiler doesn't warn you that you gave a STDCALL attribute to a name you never used - doing so would probably annoy other users who include a lot of declarations for routines not currently used.
I also retract my guess that the .LIB is 64-bit. Rather, I think it is from a CDECL (C mechanism) version of the DLL, as the names all have leading underscores, and the convention on x64 is that this is omitted.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Why do forum posts not have identifying numbers on them anymore?
Steve, I believe you said in your minimal example, linking failed both with & without the underscore. I only get a linker error without the underscore, and with it links ok.
I can confirm that the .lib file is indeed 32 bit. I have another that is 64 bit. A dumpbin from the 32 has underscores, and the 64 doesn't.
The creator of these files gives me DLL files in cdecl and stdcall flavors. But only one .lib file. Not knowing any better, I took it for granted that one .lib file works for both. If stdcall requires a different .lib file, let me know and I'll ask them for it.
If you are wondering why I want to use the stdcall flavor. I call this DLL from Excel visual basic as well as fortran. So I want to use the same DLL for both.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My first two examples didn't link to any library - I was just showing the names referenced.
You must use the .LIB that corresponds to the DLL you are using. If you do that, and correct the directives in your source, it should work fine.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I found a google page that shows Intel's MKL has DLL's on both flavors, and the LIB files are different. So I have asked my supplier for a proper stdcall-LIB file.
If I got it right (always doubtful), a "correct" directive will not have an underscore at the front of the name, and BIND(C, name='xyz') will be in the declaration, and I won't need any !DIR$ ATTRIBUTES VALUE statements.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page