- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
typedef void (__stdcall *f_func_type_stdcall)(float*, unsigned char[]);
typedef void (__cdecl *f_func_type_cdecl)(float*, unsigned char[]);
f_func_type_stdcall pfunc_stdcall = NULL;
f_func_type_cdecl pfunc_cdecl = NULL;
int LoadDLL (const string& dllname, const bool convCdecl)
{
HMODULE mydll = NULL;
mydll = LoadLibrary(dllname.c_str());
if (mydll)
{
if (conv)
{
pfunc_cdecl = (f_func_type_cdecl) GetProcAddress(mydll, "FUNCNAME");
}
else
{
pfunc_stdcall = (f_func_type_stdcall) GetProcAddress(mydll, "_FUNCNAME@8");
}
}
return(0);
}
What type should I pass from Fortran to contain the value of f_func_type_cdecl or f_func_type_stdcall? I couldn't find an equivalent to void*, and have tried various permutation of INT(KIND=4) and int POINTER without success.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The type C_FUNPTR from ISO_C_BINDING would be the appropriate type to pass and return the function pointer from C. You could then use C_F_PROCPTR to create a Fortran procedure pointer that can call the function.
As for void *, there is no current standard way to express this in Fortran, though one has been proposed. If you use C_F_PROCPTR, you can convert the C pointer to a Fortran function pointer of whatever type you want.
To get STDCALL, you will need to insert !DEC$ ATTRIBUTES STDCALL into the abstract interface for the procedure pointer (see sample below).
[plain]abstract interface subroutine subint (x) !dec$ attributes stdcall :: subint real x end subroutine subint end interface procedure(subint), pointer :: p[/plain]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks. I have declared an interface with a C_FUNPTR parameter, although when control returns to Fortran after calling the dll, the variable dfunc shows "undefined address".
INTERFACE
FUNCTION FuncInit [C, ALIAS: '_FuncInit'] (sArr, inFile, outFile, conv, dfunc)
import :: C_FUNPTR
INTEGER FuncInit
REAL sArr [REFERENCE]
INTEGER(KIND=1) inFile [REFERENCE]
INTEGER(KIND=1) outFile [REFERENCE]
CHARACTER conv [REFERENCE]
TYPE(C_FUNPTR) dfunc [REFERENCE]
END
END INTERFACE
INTEGER(KIND=1) L_INI(256), L_OUTI(1024)
CHARACTER L_INC*256, L_OUTC*1024
EQUIVALENCE (L_INI, L_INC), (L_OUTI, L_OUTC)
TYPE(C_FUNPTR) :: C_DFUNC = C_NULL_FUNPTR
INTEGER retVal
!INFILE, OUTNAME, C_CONV, R_ARR populated elsewhere
L_INC = INFILE
L_OUTC = OUTNAME
retVal = FuncInit(R_ARR(1),L_INI(1),L_OUTI(1),C_CONV,C_DFUNC)
---------
Callee:
typedef void (__stdcall *f_func_type_stdcall)(float*, unsigned char[], unsigned char[]);
typedef void (__cdecl *f_func_type_cdecl)(float*, unsigned char[], unsigned char[]);
f_func_type_stdcall pfunc_stdcall = NULL;
f_func_type_cdecl pfunc_cdecl = NULL;
int FuncInit(float *rs, unsigned char infile[], unsigned char outfile[], char callingConv[], void (*inptr)(float*, unsigned char[], unsigned char[]))
{
//Calls function to set calling convention...
// set inptr = function ptr
inptr = pfunc_cdecl;
return(0);
}
After the C++ call C_DFUNC contains undefined address. What can I do to ensure this value is correctly passed back?
Thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FUNCTION FuncInit (sArr, inFile, outFile, conv, dfunc) BIND(C,NAME='FuncInit')
The problem you have is on the C side. The assignment to inptr isn't doing what you want - I'm not enough of a C expert to understand why. The Fortran code is passing the correct thing.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Whack an extra level of indirection in on the C inptr argument declaration and the appropriate *inptr dereference on the left hand side of the C inptr assignment expression and see how you go. Alternatively, make the C function return the pointer-to-function. Similar level-of-indirection issue (but going the other way) discussed here.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve - lesson learnt! I've tidied up the interface, and will purge other examples of Microsoft pollution I come across.
Adding an extra layer of indirection did the trick with the function pointer.
A more useful design for my purposes would be to return the dll handle (HMODULE) from the initialisation function, and then pass the handle back to a C++ dll function loader/caller when required. To acheive this I am passing an 8-byte int ref from Fortran to the callee (C++ long). This works ok but I get a C++ warning related to 64-bit portability when I cast the long back to an HMODULE.
I understand I can call LoadLibrary from Fortran but the only examples I can find use a 4-byte int as the handle -is this the closest equivalent to HMODULE? Might this also have repurcussions for 64-bit portability?
Thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Use INTEGER(HANDLE) for Windows handles - HANDLE is defined if you use any of the Win32 modules.
A sample using LoadLibrary is included with the compiler, under the DLL subfolder.
- 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