Calling a Fortran subroutine from C# at the console - c#

I want to call a Fortran subroutine from C# using commands entered at the console.
I have been trying for two days now, reading many web pages, and following much advice, but with no success.
Here is a typical example of my many failed attempts.
Using a text editor (Notepad) I create this file called "fdll.f90"
module fdll
implicit none
contains
subroutine testFDLL(char)
character(12) :: char
write(6,*)" Hello FORTRAN : let us do something ...",char
return
end
end module
At the MS-DOS console (CMD.EXE), I type the following command and press "Enter" :
C:\Compilers\fortran\mingw32\bin\gfortran.exe -shared -o fdll.dll fdll.f90
Two new files appear, named "fdll.dll" and "fdll.mod".
Using the Monodevelop C# text editor, I create the following C# source file called "DLLImport.cs"
using System;
using System.Runtime.InteropServices;
public static class DLLImport
{
public static void Main(string[] args)
{
RunFortranDLL ();
}
public static void RunFortranDLL()
{
FortranLib.testFDLL("Please work!");
}
}
public static class FortranLib
{
private const string dllName = "fdll.dll";
[DllImport(dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void testFDLL(string Plea);
}
At the console, I enter the following command :
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /t:exe /out:go.exe DLLImport.cs
A new file appears called "go.exe". I type "go".
The result is a popup window telling me "go.exe has stopped working". It gives me the option to close the program. At the MS-DOS console, the following message has appeared:
Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
at Fortran.Lib.testFDLL(String Plea)
at DLLImport.Main(String[] args)
What have I done wrong? How can I make this work?
I am using a 64-bit SONY laptop running Windows 8.1. I am using the latest verion of gfortran (i686-w64-mingw32).
UPDATE: I modified the Fortran source code to allow for ISO_C_BINDING (following Pierre's suggestion). The new version is:
module fdll
contains
subroutine testFDLL(char) bind(C)
USE ISO_C_BINDING
character (C_CHAR) :: char(20)
write(6,*)" Hello FORTRAN : let us do something ..."
return
end subroutine
end module
I also modified the C# source code to make it send the character string into Fortran as an array (as explained here: http://www.luckingtechnotes.com/calling-fortran-dll-from-csharp/). The new C# code is:
using System;
using System.Runtime.InteropServices;
public static class DLLImport
{
public static void Main(string[] args)
{
RunFortranDLL ();
}
public static void RunFortranDLL()
{
FortranLib.testFDLL(ToCharacterArrayFortran("Please work!",20));
}
public static char[] ToCharacterArrayFortran(this string source, int length)
{
var chars = new char[length];
int sourceLength = source.Length;
for (int i = 0; i < length; i++)
{
if (i < sourceLength)
chars[i] = source[i];
else
chars[i] = ' '; // Important that these are blank for Fortran compatibility.
}
return chars;
}
}
public static class FortranLib
{
private const string dllName = "fdll.dll";
[DllImport(dllName, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void testFDLL(char[] Plea);
}
I made no changes to the command line arguments running the compilers ; neither compile, gfortan nor csc, complained about any of these changes.
RESULT: when I run the program (enter "go") the same error message appears.
Can somebody please explain what is wrong, or missing, with what I have done. Is it really this hard getting C# to send a character string into a Fortran subroutine?

I just try to show how to interface this FORTRAN code with C, this does not fully answer your question, but if you know how to interface C (pretend the FORTRAN as C) with C#, it should help.
!fortran code, named as x.f90
module fdll
implicit none
contains
subroutine testFDLL(str, n) bind(c, name='testFDLL_as_C')
use ISO_C_BINDING
integer(c_int), value :: n
character(kind=c_char), intent(in) :: str(n)
write(6,*)" Hello FORTRAN : let us do something ...",str
return
end
end module
And the C code calling FORTRAN subroutine.
//c code explicitly link. named as y.c
#include <stdio.h>
#include <string.h>
int main()
{
void testFDLL_as_C(char *str, int n);
char str[] = "Hello from C";
testFDLL_as_C(str, strlen(str));
return 0;
}
You can pretend your FORTRAN subroutine as a C function and call from C# as usually ways. The C test code gives:
Hello FORTRAN : let us do something ...Hello from C
You can also implicitly link with the dynamic library as the following (note, ignore all error check and close of resources for shorter example).
//implicit link. named as z.c
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
int main()
{
void (*func_from_so_f90)(char *str, int n);
char str[] = "Hello from C, again, using dynamic dlopen()";
void *handle = dlopen("./libxf90.so", RTLD_LAZY);
func_from_so_f90 = dlsym(handle, "testFDLL_as_C");
func_from_so_f90(str, strlen(str));
return 0;
}
The command to compile them (on linux) are
gfortran -o libxf90.so -shared -fPIC x.f90
gcc -o yout y.c ./libxf90.so
gcc -o zout z.c -ldl
The output of the 2nd program is like:
Hello FORTRAN : let us do something ...Hello from C, again, using dynamic dlopen()

The C# definition is incorrect. It should be
public static extern void __MOD_fdll_testFDLL(byte[] Plea);
see how to call a Fortran90 function included in a module in c++ code?
You can use nm, if you have it, or the dependency walker to find out what the exported symbols are.
Note that C# char is 2 bytes, Fortran char is 1 byte and the way arrays are stored is different in both Fortran and C#.
If this is just an interoperability test, try working with just integers first and make sure that works. Then move on to a single character (byte) and then on to arrays. Don't go on to arrays in your first attempt.

i686-w64-mingw32 means that you need to compile C# with x86 (not AnyCPU)

Related

How to call C++ code, and the code it calls, from C#

TL;DR
I have legacy c++ code which does stuff (sometimes returns stuff), calls other cpp code, but is not a full class/obj. This code I cannot alter. I am making fresh c# code which I am looking to call the c++ code from. I don't understand whether to create a dll that calls the original legacy c++, or create a CLR?? which also calls the legacy cpp. Below I have example code that I have implemented (with problems).
Main
I have legacy.cpp and legacy.h which I can not alter.
This is not a class/object and only has public functions, values, and #defines.
legacy.cpp and .h both #include other files and cpp libraries to do its job.
I have a new project where I can add C#, C++ code
I am having trouble understanding what I need to do/research in order to call any of the functions defined in legacy.cpp (or the values/defines) from within my new C# code.
Some of what I have looked at include
Managed CLR wrappers
https://drthitirat.wordpress.com/2013/06/03/use-c-codes-in-a-c-project-wrapping-native-c-with-a-managed-clr-wrapper/
https://web.archive.org/web/20140806022309/http://blogs.msdn.com/b/borisj/archive/2006/09/28/769708.aspx
DLLs??
How to call C++ DLL in C#
CLR
I have currently tried to create a CLR (thought I feel like it is not what I need in this situation), but I had problems in the clr_wrapper.cpp, it could not find the reference to foo()
//Wrapper.cpp
#include "Wrapper.h"
#include "abs\path\to\legacy\code\legacy.h"
#include "abs\path\to\legacy\code\legacy.cpp"
int foo_Wrapper()
{
return foo(); //int foo() is declared in legacy.h and defined in legacy.cpp
}
#pragma once
#include "abs\path\to\legacy\code\legacy.h"
#include "abs\path\to\legacy\code\legacy.cpp"
using namespace System; //What things use this?
//Can I just prepend System:: to whatever needs it?
namespace Wrapper {
public ref class Wrapper
{
public:
int foo_Wrapper();
};
}
the foo_Wrapper() is not able to call foo().
My confusion with this method is that it looks like I would need to make the clr wrapper an object class with member functions that will be called as needed. Leading to a syntax of obj.foo(). Is this what needs to be done if I chose to do some sort of CLR wrapper?
DLL
I have also looked at making this all a dll like in (How to call C++ DLL in C#)
However I am confused on setting this up. My current idea is to have a cpp dll call the original cpp (ie create legacyDll.dll which would make calls to foo(), then my main c# would call the __declspec(dllexport) functions defined within extern "C" {}
current setup (from "How to call c dll in c sharp")
dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
extern "C"
{
__declspec(dllexport) void bar_Dll()
{
cout << "calling bar() in legacy code" << endl;
}
__declspec(dllexport) int foo_Dll()
{
cout << "calling foo() in legacy code" << endl;
//realistically I would have,
//return foo()
}
}
Class1.cs
using System;
using System.Runtime.InteropServices;
namespace Test_DLL_Calling
{
class Class1
{
[DllImport("dllmain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void bar_Dll();
[DllImport("dllmain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int foo_Dll();
public static void Main(string[] arg)
{
bar_Dll(); //The specified module could not be found (Exception)
Console.WriteLine(foo_Dll()); //Im guessing this will also ^^
}
}
}
This part I don't follow. What and why are the attributes done the way they are?
Alright, so you have a header and cpp which you need to use. In order to use it you have to have make the c++ into C code. This is pretty much what you see in the DLL example code that you showed. However, I do suggest that you remove the includes from the header as I'm unsure how that would translate to the C code. Put the includes in the cpp files instead.
I find it rather difficult to answer this questions other than just showing a whole bunch of example code. Full code in: https://github.com/ze413X/Cpp-Code-Gems/ Where "CSharpExampleUsingCpp" calls from MainWindow.xaml.cs the "DLLExample" which uses the file in the directory includes and source.
DLL:
The header which is exposing functions to be used:
#pragma once
#define DLLExport _declspec(dllexport)
extern "C" DLLExport void __cdecl GetCppText(char* str, int* strLength);
extern "C" DLLExport void __cdecl DLLPrint();
.cpp
#include "../includes/DLLExampleCode.h"
#include <string>
#include <iostream>
void __cdecl GetCppText(char* str, int* strLength)
{
std::string text = "This is called from within the DLL.\0";
if (*strLength < text.length() || str == nullptr)
{
return;
}
memset((void*)str, 0, (*strLength) * sizeof(char));
strcpy_s(str, *strLength,text.c_str());
*strLength = text.length();
}
void __cdecl DLLPrint()
{
std::cout << "This is printed from inside DLLExample.dll.\n";
}
C#:
using System.Runtime.InteropServices;
namespace CSharpExampleUsingCpp
{
public partial class MainWindow : Window
{
const string PATH = "DLLExample.dll";
[DllImport(PATH, CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern void GetCppText(byte[] str, out System.Int32 strLength);
....
private void CppInteropButton_Click(object sender, RoutedEventArgs e)
{
System.Int32 size = 256;
System.Byte[] str = new byte[size];
for (int i = 0; i < size; i++)
{
str[i] = (byte)'1';
}
GetCppText(str, out size);
string result = System.Text.Encoding.UTF8.GetString(str, 0, size);
CppInteropButtonTextBox.Text = result;
}
Although, rereading my solution of obtaining a string might not be the best way of doing it. You could probably marshal that thing to avoid all this stupid char* conversions. I probably had some good reason at that point in time when I wrote it. That should be much easier to google though.

Passing Pointer between C++ Project and C# Project without using unsafe on C# project

Stuck in very naive issue. I have two project, One in C++ and other in C#. Idea is to use C++ project as wrapper around some C libs. and performing actual logic in C#.
Passing the Value type is very convenient. But with reference type i am having hard time WITHOUT USING unsafe or DllImport attribute.
C++
Cryptoki.Wrapper.h File
using namespace System;
#pragma comment(lib, "legacy_stdio_definitions.lib")
namespace CryptokiWrapper {
public ref class CryptokiInit
{
public:
char* TESTString(char* test);
double TESTDouble(double test);
};
}
Cryptoki.Wrapper.cpp File
#include "stdafx.h"
#include "Cryptoki.Wrapper.h"
using namespace std;
using namespace CryptokiWrapper;
char* CryptokiInit::TESTString(char* test)
{
char* r = test;
return r;
}
double CryptokiInit::TESTDouble(double test)
{
unsigned long int r = test;
return r;
}
C# Code
using System;
using System.Runtime.InteropServices;
using CryptokiWrapper;
namespace CallCryptoki
{
class Program
{
//[MarshalAs(UnmanagedType.LPTStr)]
//public String msg = "Hello World";
static void Main(string[] args)
{
CryptokiInit ob = new CryptokiInit();
//This Works
doubled d = ob.TESTDouble(99);
//But having hard time accepting the char* reference
//or sending string as refrence without using unsafe
// like
string text = "Hello World!";
string res = (*something*)ob.TESTString((*something*)text);
}
}
}
IS there any type of cast (i.e. something) .....
is there anyway where i am able to easily perform this action. (only reference transfer will be sufficient, then i can build string or object)
Like on another function works, using the double as parameter and return type.
Though above example speak of string only, but would like to understand as concept so that i could write interop for any reference type between two project(i.e. C# and C++)
Thanks in advance for help!
First, that's not plain C++, but C++/CLI - which is primarily designed for managed/unmanaged code interoperability.
Your C++/CLI function can use .NET's string type like this:
System::String^ TESTString(System::String^ test);
^ means managed reference, think of it as the managed equivalent of *.
Now, to use the string data in pure C++, you have two choices:
marshal it - see Overview of Marshaling in C++
For instance, if you need to convert it to a const char*, do the following:
#include <msclr/marshal.h>
msclr::interop::marshal_context ctx;
auto testCStr = ctx.marshal_as<const char*>(test);
// testCStr is freed when ctx goes out of scope
This will copy the string data, as the memory representation needs to change from 2 bytes par character to a single one.
access the memory directly as const wchar_t*. You need to pin the string beforehand so it's not moved by the GC.
#include <vcclr.h>
pin_ptr<const wchar_t> testCStr = PtrToStringChars(test);
// testCStr behaves just like a const wchar_t*
Do not modify the string data this way.
To send a string back to the managed side, you can either use marshal_as<System::String^>(yourCString), or call gcnew System::String(yourCString);

Is gcroot and /clr mixed mode and a C++ wrapper the shortest path from pure C to C#?

So I am writing a plug-in DLL which is pure C (and a heap of foreign includes), but most of the real code is in an existing C# class library. I'm looking for the shortest path from C (not C++) to C#. The foreign includes are not C++ safe.
There are heaps of samples around for C++, not much for pure C.
It seems I should be able to compile the whole DLL as /clr but compile the C as not; then include in the same DLL a C++ wrapper that presents a C API but contains managed code to call the C# class.
So instantiate the C# class and hang onto it in a gcroot in a C++ class, and pass the C++ class pointer as a void* back for the the C code to keep for future calls.
Quite a few details to get right, but not all that much code. Is there a better way?
Thought it was time to add a bit of code.
// Wrapper.h
#pragma once
// API for call by C
#ifdef __cplusplus
extern "C" {
#endif
void* wrap_create();
void wrap_doit(void* wrapper, char* input, char* output, int maxlen);
#ifdef __cplusplus
}
#endif
// Wrapper.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <vcclr.h>
#include "Wrapper.h"
using namespace System;
class Wrapper {
public:
gcroot<Wrappee::Evaluator^> eval;
Wrapper() {}
};
void* wrap_create() {
Wrapper* w = new Wrapper();
w->eval = gcnew Wrappee::Evaluator();
return w;
}
void wrap_doit(void* wrapper, char* input, char* output, int maxlen) {
Wrapper* w = (Wrapper*)wrapper;
String^ s = w->eval->Doit(gcnew String(input));
pin_ptr<const wchar_t> wch = PtrToStringChars(s);
wcstombs(output, wch, maxlen);
}
// Wrappee.cs
using System;
namespace Wrappee {
public class Evaluator {
string _s;
public static Evaluator Create() {
return new Evaluator {
_s = "wrapped evaluator"
};
}
public string Doit(string s) {
return _s + ":" + s;
}
}
}
Why wouldn't that work? The code is based on this link: https://msdn.microsoft.com/EN-US/library/481fa11f%28v=VS.140,d=hv.2%29.aspx.
The answer is no, that won't work. The managed class depends on the CLR runtime, which needs to be hosted by the application. For a managed app that happens automatically (mscoree.dll during startup), but for a native app there is no host so no CLR.
So we have to provide one. As #hanspassant helpfully pointed out, this is "Reverse P/Invoke" and it really is different. You have to get there by the COM hosting interfaces, specifically ICLRMetaHost.
And the good news is that there is a sample here to show how it's done: https://code.msdn.microsoft.com/windowsdesktop/CppHostCLR-e6581ee0.
There are other samples too: search for CppHostCLR.

C from C#: string as parameter and return value?

I'm calling the doThis function in a .c file in a Win32 DLL.
#include <stdio.h>
__declspec(dllexport) double doThis( char *message)
{
printf("do nothing much");
return 32.5;
}
using this calling code:
[DllImport(#"\\vmware-host\Shared Folders\c-sharp\Hot\MusicIO\Debug\HelloWorld.dll",
CallingConvention=CallingConvention.Cdecl)]
public static extern double doThis(string message);
private void button1_Click(object sender, EventArgs e)
{
double returned = doThis("what 2");
MessageBox.Show("Click " + returned);
}
That works fine, but I want the function to return a char *... and return the message variable.
When I change the doThis to return a char *, and the calling code to expect a string, the Win32 Host crashes at runtime.
Any advice?
[weirdly, I think I had this working just before]
Let's suppose for a while this signature worked:
__declspec(dllexport) char* doThis(char* message)
You call it from C# and then you have a char*. You copy it over to a string, and then... then what? What do you do with that char*?
Do you call free on it? The free of which C runtime library by the way? Or maybe you shouldn't since the pointer may be from static memory? You don't know, and the .NET mashaller doesn't know either.
The proper way to handle this is to pass a second char* parameter, that points to some buffer you allocated, and you are responsible for freeing.
Well, in C# that doesn't really have to be you. The marshaller can handle this for you.
So define a signature like this:
__declspec(dllexport) double doThis(char* message, char* output, int maxOutputLength)
The maxOutputLength parameter is a security measure, to let your C code know the maximum length of the message. Use it as you see fit in your C code.
Note: In C++ code, message would be a const char*, while output would remain a char*.
On the C# side, the signature would involve a StringBuilder:
[DllImport(#"HelloWorld.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern double doThis(string message, StringBuilder output, int maxOutputLength);
Then, you allocate a StringBuilder with some initial capacity, and pass it that:
var output = new StringBuilder(1024);
double returned = doThis("what 2", output, output.Capacity);
var outputStr = output.ToString();
And the marshaller handles the plumbing for you.

Call C++ method from .NET

I have a dll for third party app and normally communicate with it via Named Pipes. But NPs works only when the other app is started. Can I directly call a method from the dll to see its version.
C++ VS2012
#ifdef MTFST_EXPORTS
#define MTFST_API __declspec(dllexport)
#else
#define MTFST_API __declspec(dllimport)
#endif
#define LIBRARY_VERSION "3.0"
....
using namespace std;
MTFST_API char *__stdcall FST_LibraryVersion()
{
return LIBRARY_VERSION;
}
I tried the following code, but it doesn't work. .NET 4.
internal class Program
{
[DllImport("Library.dll")]
private static extern char[] FST_LibraryVersion();
private static void Main(string[] args)
{
Console.WriteLine(new string(FST_LibraryVersion()));
}
}
.NET arrays aren't compatible with raw pointers. You'll need to either use IntPtr or pass in a destination buffer to the function:
void __stdcall FST_LibraryVersion(char *dest)
{
strcpy(dest, LIBRARY_VERSION);
}
Obviously, you'll need to include checks to prevent buffer overflow.
Also, see PInvoke for C function that returns char *

Categories