- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
How to declare or transform cstr to use in OpenFileMapping? Previously I had tested what ToCharArray result got passed to fortran as cstr and all was correct including trailing 0.
string smf = "testf";
char[] acmf = smf.ToCharArray();
char[] acmf0 = new char[smf.Length + 1];
for (int i=0;i<smf.Length;i++) acmf0[i] = acmf[i];
acmf0[smf.Length] = (char)0;
int iz = smf.Length +1;
int iy = test2( ref acmf0, ref iz)
integer function test2(cstr, ilen)
!DEC$ ATTRIBUTES DLLEXPORT, alias : "test2" :: test2
use,INTRINSIC :: ISO_C_BINDING
use kernel32
type(c_ptr), intent(in) :: cstr
!...
hmmf=OpenFileMapping(dwDesiredAccess,FALSE,cstr)
produces
error #6633: The type of the actual argument differs from the type of the dummy argument. [CSTR]
From user32.f90
INTERFACE
FUNCTION OpenFileMapping( &
dwDesiredAccess, &
bInheritHandle, &
lpName)
import
integer(HANDLE) :: OpenFileMapping ! HANDLE
!DEC$ ATTRIBUTES DEFAULT, STDCALL, DECORATE, ALIAS:'OpenFileMappingA' :: OpenFileMapping
integer(DWORD) dwDesiredAccess ! DWORD dwDesiredAccess
integer(BOOL) bInheritHandle ! BOOL bInheritHandle
!DEC$ ATTRIBUTES REFERENCE, IGNORE_LOC, ALLOW_NULL :: lpName
character*(*) lpName ! LPCSTR lpName
END FUNCTION
END INTERFACE
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Try:
integer function test2(cstr, ilen)
!DEC$ ATTRIBUTES DLLEXPORT, alias : "test2" :: test2
use,INTRINSIC :: ISO_C_BINDING
use kernel32
character(len=ilen), intent(in) :: cstr
!...
hmmf=OpenFileMapping(dwDesiredAccess,FALSE,cstr)
Jim Dempsey
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Try:
integer function test2(cstr, ilen)
!DEC$ ATTRIBUTES DLLEXPORT, alias : "test2" :: test2
use,INTRINSIC :: ISO_C_BINDING
use kernel32
character(len=ilen), intent(in) :: cstr
!...
hmmf=OpenFileMapping(dwDesiredAccess,FALSE,cstr)
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Works!
static class Program
{
[DllImport("D:\\c\\vs2022\\mmff\\fDll1\\x64\\Debug\\fdll1.dll")]
static extern unsafe int test3( char[] aC, ref int ilength);
static unsafe void Main(string[] args)
{
System.IO.MemoryMappedFiles.MemoryMappedFile mmf = System.IO.MemoryMappedFiles.MemoryMappedFile.CreateNew("testf", 42);
string smf = "testf";
char[] acmf = smf.ToCharArray();
char[] acmf0 = new char[smf.Length + 1];
for (int i=0;i<smf.Length;i++)
acmf0[i] = acmf[i];
acmf0[smf.Length] = (char)0;
int iz = smf.Length +1;
int iy = test3( acmf0, ref iz);
}
}
integer function test3(lpname, ilen)
!DEC$ ATTRIBUTES DLLEXPORT, alias : "test3" :: test3
use,INTRINSIC :: ISO_C_BINDING
use user32
use kernel32
!use ifwin
character(len=ilen), intent(in) :: lpname
integer, intent(in) :: ilen
!
integer :: ilen_max = 512
integer :: i
integer :: dwDesiredAccess = Z'0f001f'
integer(8) :: xptr=0
integer(8) :: hmmf=0
integer :: iunmap=0
integer :: ihclose=0
!
hmmf=OpenFileMapping(dwDesiredAccess,FALSE,lpname)
if (hmmf == 0) then
test3=-1
return
else
xptr = MapViewOfFile(hmmf,dwDesiredAccess,0,0,42)
iunmap = UnmapViewOfFile(xptr)
ihclose = CloseHandle(hmmf)
end if
test3=ilen
return
end function test3
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Another question about int(8) ::xptr. It was the only thing I found that would not give error in MapViewOfFile, but now I find no way to convert to cptr with the intent of reading/writing to the array. I had hoped to convert to fptr array (0:ilen).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The return of MapViewOfFile is of (C) type LPVOID. While on 64-bit build this would be handled with integer(8), on a 32-bit build this would be incorrect.
If instead, as you have USE KERNEL32 in your procedure, you can then use the "Windows" types that are defined therein. Example
integer(LPVOID)
*** In your code above, you have initialization of the variables when they are declared.
There are two aspects to this in Fortran that are different from C/C++ and might bight you in the ...
1) variables that are initialized at declaration (Fortran speak is defined at....) have attribute SAVE (C analog to static). This can make your procedure .NOT. thread-safe.
2) Initialization is made in the load/binary image and not at execution time. IOW these will not be re-initialized at every call.
I suggest you not, initialize at declaration (unless you absolutely know this procedure will be called only once). IOW if you foresee mapping multiple files or different sections of the same file you may experience the programming error.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Just before your reply I found the integer(LPVOID) and started trying to use unsuccessfully in the sense that I'm trying make a char(1) array that I can read/write that would alter memory mapped file. The points 1 and 2 you make I will have to remember and take care of in the code once I can get the basic array to work.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I guess I should ask "Is there a way to create a integer(1) array from a non null integer(LPVOID)?"
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
xptr = MapViewOfFile(hmmf,dwDesiredAccess,0,0,42)
the first 0 is the high 32-bit offset in the file (don't know why MS has this "backwards")
the second 0 is the low 32-bit offset in the file
and the 42 is the size of the object
For use in Fortran, you would likely want to use the returned address as one of:
character(len=42) :: charptr
character(len=1) :: chararray(42)
integer(1) :: int1array(42)
The 42, in your code would likely be replaced with a variable (to facillitate returning different object types/sizes)
You may want to create a function that returns one of:
type(yourObject), pointer :: ret
character(len=yourLen), pointer :: ret
character(len=1), pointer :: ret(youLen)
integer(1), pointer :: ret(youLen)
or NULLIFY the return pointer in event of error.
You would make use of the C_F_POINTER intrinsic to convert the LPVOID (if it complains, you may need to convert the LPVOID into C_PTR first)
function test3(lpname, ilen) result(ret)
!DEC$ ATTRIBUTES DLLEXPORT, alias : "test3" :: test3
use,INTRINSIC :: ISO_C_BINDING
use user32
use kernel32
!use ifwin
character(len=ilen), intent(in) :: lpname
integer, intent(in) :: ilen
type yourObjectType
integer(1) :: blob(42)
end type yourObjectType
type(yourObjectType), pointer :: ret
!
integer, parameter :: ilen_max = 512
integer :: i
integer, parameter :: dwDesiredAccess = Z'0f001f'
integer(8) :: xptr
integer(8) :: hmmf
integer :: iunmap
integer :: ihclose
type(c_ptr) :: cptr
!
ilen_max = 512
dwDesiredAccess = Z'0f001f'
xptr=0
hmmf=0
iunmap=0
ihclose=0
hmmf=OpenFileMapping(dwDesiredAccess,FALSE,lpname)
if (hmmf == 0) then
nullify(ret)
return
else
xptr = MapViewOfFile(hmmf,dwDesiredAccess,0,0,sizeof(ret))
call C_F_POINTER(transfer(xptr,cptr), ret)
! here is where you either return ret or use ret
! the unmap and close would occur on other call
! the hmmf and xptr would have to be saved somewhere
! if returning object pointer
iunmap = UnmapViewOfFile(xptr)
ihclose = CloseHandle(hmmf)
end if
return
end function test3
*** untested code
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This works in a primitive way:
static class Program
{
[DllImport("D:\\c\\vs2022\\mmff\\fDll1\\x64\\Debug\\fdll1.dll")]
static extern unsafe int test3( char[] aC, ref int ilength, ref int immflen);
static unsafe void Main(string[] args)
{
int immf_len = 42;
byte* bpoke = null;
System.IO.MemoryMappedFiles.MemoryMappedFile mmf = System.IO.MemoryMappedFiles.MemoryMappedFile.CreateNew("testf", immf_len);
System.IO.MemoryMappedFiles.MemoryMappedViewAccessor view = mmf.CreateViewAccessor();
view.SafeMemoryMappedViewHandle.AcquirePointer(ref bpoke);
string smmf = "abcdefghijklmnopqrstuvwxyz0123456789<>^!=;";
if (smmf.Length > immf_len) smmf = smmf.Substring(0, immf_len);
char[] acmmf = smmf.ToCharArray();
for (int i = 0; i < 42; i++) *(bpoke + i) = (byte)acmmf[i];
string smf = "testf";
char[] acmf = smf.ToCharArray();
char[] acmf0 = new char[smf.Length + 1];
for (int i=0;i<smf.Length;i++)
acmf0[i] = acmf[i];
acmf0[smf.Length] = (char)0;
int iz = smf.Length +1;
int iy = test3( acmf0, ref iz, ref immf_len);
}
}
! fdll1.f90
!
! FUNCTIONS/SUBROUTINES exported from fdll1.dll:
! fdll2 - subroutine
!
! implicit none
!module fmdll1
!
!integer(8) :: hMapFile=0
!integer(8) :: hmmf=0
!
!end module fmdll1
!
integer function test3(lpname, ilen, immflen)
!DEC$ ATTRIBUTES DLLEXPORT, alias : "test3" :: test3
use,INTRINSIC :: ISO_C_BINDING
USE, INTRINSIC :: iso_fortran_env
use user32
use kernel32
character(len=ilen), intent(in) :: lpname
integer, intent(in) :: ilen
integer, intent (in):: immflen
!
integer(1), pointer :: fptr(:)
type(c_ptr) :: cptr
type(c_ptr) :: cdata
integer :: ilen_max = 512
integer :: i
integer :: dwDesiredAccess = Z'0f001f'
integer(LPVOID) ::cint=0
integer(8) :: hmmf=0
integer :: iunmap=0
integer :: ihclose=0
!
hmmf=OpenFileMapping(dwDesiredAccess,FALSE,lpname)
if (hmmf == 0) then
test3=-1
return
else
cint = MapViewOfFile(hmmf,dwDesiredAccess,0,0,immflen)
cdata=transfer(cint,cptr)
call c_f_pointer(cdata,fptr,[immflen])
fptr(4)='D'
!
open(1001, file = 'mmf.dat', status = 'REPLACE', access='STREAM')
write(1001),fptr
close(1001)
!
iunmap = UnmapViewOfFile(cint)
ihclose = CloseHandle(hmmf)
end if
test3=ilen
return
end function test3
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Glad that you at least have a starting point. I assume you will rework test3 into a series of get/put functions.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, there are many worms in this can like volatile, exchange, spin waits and locks equivalence.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>volatile, exchange, spin waits and locks
Then this indicates that the code is currently threaded (but not necessarily via OpenMP). Is this the case?
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I did this once in c++to do multiprocess and multithreading and it seemed like an interesting adventure.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page