- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was working on a c# memory mapped file and view initializer for access by a fortran dll when I had passed from C#. I did not even know C# had unsafe as a option, so I thought ToCharArray was native without checking. As the debugger in C# would not expand the pointer to mmf to show an array as in
byte* pmmf = null;
mmfvw.SafeMemoryMappedViewHandle.AcquirePointer( ref pmmf);
I decided to write c# code in cpp with clr(which expands unsigned char * pmmf in debugger with pmmf,256). Since C# string=CPP/System::String, I had to correct, realized it was a wchar_t System.Array, and the implication was Fortran supported converting .net arrays to fortran arrays via cptr as if they were native. Did I fall off the turnip truck again?
using namespace System;
using namespace System::IO::MemoryMappedFiles;
using namespace System::IO;
using namespace System::Runtime::InteropServices;
public ref class Fmmf {
public: static MemoryMappedFile^ mmf(String^ sID, int ilength, String^ sdisk) {
MemoryMappedFile^ mmfx;
long long llen = -1;
try
{
mmfx = MemoryMappedFile::OpenExisting(sID);
}
catch (FileNotFoundException^ e) {
try
{
mmfx = MemoryMappedFile::CreateFromFile(sdisk, FileMode::OpenOrCreate, sID, ilength);
// file not preexist
MemoryMappedViewAccessor^ accessor = mmfx->CreateViewAccessor(0, ilength);
int inew = accessor->ReadInt32(0);
//file just created
if (inew != 0x00545257)
{
array <Byte>^ aBini = gcnew array <Byte>(ilength);
aBini[0] = (Byte)'W'; aBini[1] = (Byte)'R'; aBini[2] = (Byte)'T'; aBini[3] = 0;
for (int i = 4; i < ilength; i++) aBini[i] = (Byte)'A';
for (int i = 4; i < ilength; i++) accessor->WriteArray(0, aBini, 0, ilength);
accessor->Flush();
//mmfx = MemoryMappedFile.CreateOrOpen(sID, ilength);
}
}
catch (Exception^ e)
{
mmfx = nullptr;
Console::WriteLine(e->Message);
}
}
if (mmfx != nullptr)
{
FileInfo^ fi = gcnew FileInfo(sdisk);
llen = fi->Length;
}
return(mmfx);
}
};
//DllImportAttribute
[DllImport("D:\\c\\vs2022\\mmff\\fDll1\\x64\\Debug\\fdll1.dll")]
extern int test3(array<wchar_t>^ aC,int *ilength, int *immflen);
int main(array<System::String ^> ^args){
int fixsz = 0x100;
int ilen = 0;
String ^smf = "test_so";
array <wchar_t>^ wac = smf->ToCharArray();
Array::Resize<wchar_t>(wac, wac->Length + 1);
wac[wac->Length - 1] = 0;
String ^sdf = "D:\\c\\vs2022\\mmff\\mmfcs\\mmfdf" + "\\" + smf;
MemoryMappedFile ^mmf = Fmmf::mmf(smf, fixsz, sdf);
MemoryMappedViewAccessor ^mmfvw = mmf->CreateViewAccessor();
unsigned char * pmmf = nullptr;
mmfvw->SafeMemoryMappedViewHandle->AcquirePointer(pmmf);
pmmf[8] = (char)'P';
ilen = wac->Length;
int ix = test3(wac, &ilen,&fixsz);
mmfvw->SafeMemoryMappedViewHandle->ReleasePointer();
//
//while (true) {
// mmfvw.Flush();
// Thread.Sleep(180000);
//}
return 0;
}
[DllImport("D:\\c\\vs2022\\mmff\\fDll1\\x64\\Debug\\fdll1.dll")]
static extern unsafe int test3( char[] aC, ref int ilength, ref int immflen);
...
int immf_len = 42;
System.IO.MemoryMappedFiles.MemoryMappedFile mmf =
System.IO.MemoryMappedFiles.MemoryMappedFile.CreateNew("testf", immf_len);
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);
and Fortran
! fdll1.f90
!
! FUNCTIONS/SUBROUTINES exported from fdll1.dll:
!
! 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, volatile :: 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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It's not a case of "converting". Depending on how you declare the argument in the .NET language, simple arrays may be passed by address. Otherwise, they tend to be passed as "SafeArrays". The IFCOM module contains routines for accessing SafeArrays - there is a VB sample in the Intel Fortran samples bundle. I have not looked closely at the code you posted.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My first mistake was I thought a C# char was the same as cpp char. The C# code does not compile if the "usingSystem.Runtime.InteropServices;" is omitted. I think I will make simple example and look at call stack for char[] pass only.
Suspicion is Interop passes SafeArray to Fortran.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
String ^sdf = "D:\\c\\vs2022\\mmff\\mmfcs\\mmfdf" + "\\" + smf;
Suggest you try path combine and @ and it will be a lot easier to read. Also using a subst z: for your long name makes it easy to find.
Just a thought.
Pity that c# and Fortran are so alike and not alike.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page