Protected Memory Violation calling FORTRAN DLL from C# - c#

I am trying to call out to a legacy dll compiled from FORTRAN code. I am new to Interop, but I've read some articles on it and it seems like my case should be fairly straightforward.
The method I really want to call has a complex method signature, but I can't even call this simple GetVersion method without getting a protected memory violation.
Here's my DllImport code:
[DllImport("GeoConvert.dll",
EntryPoint="_get_version#4",
CallingConvention=CallingConvention.StdCall)]
public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPStr, SizeConst=8)]
ref string version);
Here's the FORTRAN code:
SUBROUTINE GetVer( VRSION )
C
!MS$DEFINE MSDLL
!MS$IF DEFINED (MSDLL)
ENTRY Get_Version (VRSION)
!MS$ATTRIBUTES DLLEXPORT,STDCALL :: Get_Version
!MS$ATTRIBUTES REFERENCE :: VRSION
!MS$ENDIF
!MS$UNDEFINE MSDLL
C
CHARACTER*8 VRSION
C
VRSION = '1.0a_FhC'
C
RETURN
END
Here's my unit test that fails:
[Test]
public void TestGetVersion()
{
string version = "";
LatLonUtils.GetGeoConvertVersion(ref version);
StringAssert.IsNonEmpty(version);
}
Here's the error message I get:
System.AccessViolationException
Message: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
Other things I've tried:
Using the default marshalling
Passing a char[] instead of a string (get method signature errors instead)

...snip...
OK, I got it to work, the problem was passing by ref. I'm not sure why, but this works:
...snip...
You need to pass by reference because that is the semantic being used by the FORTRAN code. The client code is passing in a buffer that the FORTRAN code is going to write to in lieu of using a return value.
...snip...
!MS$ATTRIBUTES REFERENCE :: VRSION
...snip...
This attribute in your FORTRAN code specifies that this parameter is passed by reference. That means the FORTRAN code is going to write to this address. If the DllImport doesn't declare it as a ref value also, you will get an access violation.

OK, I got it to work, the problem was passing by ref. I'm not sure why, but this works:
[DllImport("GeoConvert.dll",
EntryPoint="_get_version#4",
CallingConvention=CallingConvention.StdCall)]
public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPArray)]
byte[] version);
With this test:
[Test]
public void TestGetVersion()
{
//string version = "";
byte[] version = new byte[8];
LatLonUtils.GetGeoConvertVersion(version);
char[] versionChars = System.Text.Encoding.ASCII.GetChars(version);
string versionString = new string(versionChars);
}

Have you tried using a StringBuilder?
Create your String as a StringBuilder and pass that into the dll function.
Im unsure as to what Marashlling statement to use, perhapse the default might work.
Have a look at: Marshal C++ “string” class in C# P/Invoke
Heres a good article the might help as well: Interop Marshalling

I cannot try this solution since I do not have a FORTRAN compiler, but I think this would work for you:
[DllImport("GeoConvert.dll",
EntryPoint="_get_version#4",
CallingConvention=CallingConvention.StdCall,
CharSet=CharSet.Ansi)]
public static extern void GetGeoConvertVersion(StringBuilder version);

Thank you all guys, I've been trying to pass a string from c# to a subroutine from fortran dll and this method was the only working one among lots of others

Related

To share an exported C++ DLL event, within an external C++ Win32 Application

Have a good day!
For portability reasons, i have created a C++ DLL with almost novice C++ knowledge just by searching thousands of pages, hundreds of compiling error corrections and couple of stackoverflow questions.
It is far beyond being stable but it is working most of the time :)
Just for curiosity and modularity reasons without importing the header and the cpp file to my application, i would like to ask your advice and help:
C++ Win32 Console Application
int main()
{
HMODULE lib = LoadLibrary(L"Serial.dll");
typedef void(*void_Connect)(UINT Port, UINT Baud);
void_Connect Connect = (void_Connect)GetProcAddress(lib, "Connect");
Connect(1, 9600);
}
I want to add an event into above C++ Win32 Console application, which will be triggered or hosted by the DLL
For example, a Received_Event(const char* data) or Connected_Event(BOOL status) with parameters.
Part from the DLL
typedef void(*fpCALLBACK) (const char* aParam);
static fpCALLBACK s_pCallback = NULL;
extern "C"
{
#define DLL __declspec(dllexport)
DLL void ReceivedEventRegister(fpCALLBACK p_pCallback)
{
s_pCallback = p_pCallback;
}
DLL void evntReceived(const char *receivedData);
}
DLL void evntReceived(const char *received)
{
s_pCallback(received);
}
I want to achive something similar to this C# version, with Standard C++
private static ManagedCallbackDelegate MessageCallbackDelegate;
public delegate void ManagedCallbackDelegate(string aParam);
[DllImport("Serial.dll", EntryPoint = "ReceivedEventRegister", CallingConvention = CallingConvention.Cdecl)]
private static extern void ReceivedEventRegister(ManagedCallbackDelegate callback);
static private void serialRecieved(string data)
{
Console.WriteLine(data);
}
static void Main(string[] args)
{
MessageCallbackDelegate = new ManagedCallbackDelegate(serialRecieved);
ReceivedEventRegister(MessageCallbackDelegate);
}
With C# code above, any data received by the DLL, the serialRecieved function is called in realtime. I want to achive this with Standard C++
I want to be informed or be aware of with the DLL process in realtime, in my Win32 C++ Console Application. ( Without blocking the Win32 Console application )
No MFC. if it is possible, no Component Object Model (It is possible with C# without need to convert the DLL into a COM). if it is possible, I want to do it with Standard C++.
I am compiling things with Visual Studio 2017 Community
Please go easy with me. It is a hobby for me and i just do it in my spare time.
Questions
Can you reference me some code examples written for this purpose, you are aware of?
Is there any specific name for this kind of communication that i can Google?
Is there any approach, you can suggest?
Thank you!
Once again, thanks to #dxiv's comment; helped me a lot, to sort things out! Even, when someone tells you that it should work, you resolve 90% of the problem.
At the DLL side
DLL void evntReceived(const char *received)
{
s_pCallback(received);
}
The DLL is calling the above function all the time as soon as it receives any data. To get that data realtime in your Win32 C++ Application, you need to import the DLL function which is calling the above callback function. Which is this
DLL void ReceivedEventRegister(fpCALLBACK p_pCallback)
part of the DLL.
As the DLL function's parameter type name fpCALLBACK suggests, our function parameter has to be as it is defind in the DLL:
typedef void(*fpCALLBACK) (const char* aParam);
At the Application side
//Callback Function: A function that is passed to another function as an argument
void Event_Received(const char *recvd)
{
std::cout << recvd << std::endl;
}
int main()
{
HMODULE lib = LoadLibrary(L"Serial.dll");
typedef void(*void_Connect)(UINT Port, UINT Baud);
void_Connect Connect = (void_Connect)GetProcAddress(lib, "Connect");
// Type definition of the function pointer.
// In our case: a Void type, which takes in a
// void type function pointer with a parameter (const char *aParam)
// dllCALLBACK is just a type name; you can name it whatever you want.
typedef void(*dllCALLBACK) (void(*fpCALLBACK) (const char* aParam));
// Now we will import the function from our DLL which takes
// the same parameters as we defined above, to call
// our callback function
dllCALLBACK ReceivedEventRegister = (dllCALLBACK)GetProcAddress(lib, "ReceivedEventRegister");
// Call the callback function with the imported function above.
// And that is all there is to it. As soon as any data received
// by our DLL - our Event_Received callback function
// fires in our C++ Win32 Console Application
ReceivedEventRegister(Event_Received);
Connect(1, 9600);
}
If you are a novice like me this video may help you to understand about Callback functions.
Thank you #dxiv again, taking time to read and answer my question!

C# P/Invoke AccessViolationException when attepting to use string parameters

I'm trying to wrap a C++ dll for which I only have the header file for. The function I am trying to get working at the moment is giving me an AccessViolationException:
"Attempted to read or write protected memory.
This is often an indication that other memory is corrupt."
The C++ function prototype is:
RunSimulation( LPCSTR, LPSTR);
Meanwhile, my C# wrapper is:
[DllImport("thedll.dll", EntryPoint = "RunSimulation")]
public static extern uint RunSimulation(string simID, ref string outputID);
I suspect the problem is with the C# function, specifically with how the strings are implemented. Since I'm relatively new to platform invocation and such, I'm not sure how to proceed.
Should the string parameters be pointers to where the strings are? Or is there something else wrong with the wrapper maybe?
Edit:
This is how the function is called on the managed end of things:
string outputID = "";
try
{
RunSimulation(id, ref outputID);
}
catch (Exception e)
{
Logging.Log_Warning.SendException("Threw an exception", e);
}
Edit 2:
Upon changing the second parameter to a StringBuilder, the same exception occurs. The only difference is that the exception break doesn't stop at the line where the function is called, Visual Studio opens a new "Break" tab saying the exception happened. The function documentation recommends setting aside 16 bytes or more, so I used the capacity constructor with a values of 1024 and 4096 to test.
Edit 3:
After doing a clean and rebuild, the problem presented itself as a driver error. Since this shows that the API is functioning, the solution was indeed to change my ref string parameter to a StringBuilder as suggested in the comments.
The solution to my problem ended up being to use StringBuilder instead of String to make sure the space in memory was allocated ahead of time. So my signature ended up looking like:
[DllImport("thedll.dll", EntryPoint = "RunSimulation")]
public static extern uint RunSimulation(string simID, StringBuilder outputID);
And to use it:
string id = "someID";
int requiredSize = 512;
StringBuilder outputID = new StringBuilder(requiredSize);
RunSimulation(id, outputID);
Hope that helps!

Variable corrupted when calling C++ COM from C#

I'm calling C++ COM interface from C# code using a dll.
At the C++ side, i have a WCHAR* global variable which is updated through a method with a BSTR parameter.
The problem is that, when i first call the C++ wrapper method from C# to change the variable, everything works fine, but at the moment that i call another C++ wrapper method from C#, unexplainably the WCHAR* global variable points to a different memory position and its value gets corrupted.
Some code:
//THE C# side:
capture.filename = PATH + "\\" + DIRECTORY_NAME + "\\";
capture.MaxMinutesPerFile = MAX_MINUTE_PER_FILE;
"capture" is an object of the C++ wrapper class (i think it is autogenerated when building the C++ code to a DLL. Not my code).
"filename" property calls a "put_FileName" C++ method and "MaxMinutesPerFile" a "put_MaxMinutesPerFile" method.
//C++ code
WCHAR *m_bstFileName = L"None";
(...)
STDMETHODIMP CCaptureMF::put_FileName(BSTR PathName)
{
EnterCriticalSection(&m_critsec);
HRESULT hr = S_OK;
m_bstFileName = PathName;
LeaveCriticalSection(&m_critsec);
return hr;
}
STDMETHODIMP CCaptureMF::put_MaxMinutesPerFile(LONG Minutes)
{
MaxMinutes= Minutes;
return S_OK;
}
So, after calling "put_FileName", "m_bstFileName" is updated correctly with the "PathName" value, but just after calling "MaxMinutesPerFile" (or any other interface wrapper method), "m_bstFileName" gets corrupted pointing to a different memory position and fulfilled with strange data.
Thank you.
EDIT:
To make a buffer of "m_bstFileName" and then copy the "PathName" data, i used the following code, taking in mind that "m_bstFileName" size can change at runtime:
m_bstFileName = (wchar_t*)malloc(sizeof(PathName));
wcscpy(m_bstFileName, PathName);
That code works fine, but the rest of the program behaves bad. I´m not sure why, i should investigate more, but for now, could you analyze that pice of code and tell me if it is correct or if i should implement it in other way?
SOLUTION:
Ok, following your recomendations i have finally implemented the following code, which works perfect for the whole application:
CComBSTR m_bstFileName = L"None";
(...)
STDMETHODIMP CCaptureMF::put_FileName(BSTR PathName)
{
EnterCriticalSection(&m_critsec);
HRESULT hr = S_OK;
m_bstFileName = PathName;
if (g_pCapture)
{
g_pCapture->SetPath(m_bstFileName);
}
LeaveCriticalSection(&m_critsec);
return hr;
}
If you think that this can be implemented better, just tell.
Thank you for your help!
In the most basic case you'll need to make a buffer to do a string copy into. Same operation could be accomplished via assignment with cstring, ccombstr, std::string, etc. depending on the framework you're using.
You need to copy the string to m_bstFileName, not just assign it. Use something like
strcpy(m_bstFileName, PathName);

A call to PInvoke function xxx has unbalanced the stack

I am using C DLL in C# code (.net 4.0) in a console application and facing issue.
When I call the C method it raises the below exception.
"A call to PInvoke function 'ProcessFilesC' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature."
Here is the C code
int ProcessFilesC(
char **p_FilesOrDirs,
ImageInfoC **p_vecImageInfo,
int ***p_vecStackIndexes,
RectC ***p_vecFaces
);
Here is my C# code
[DllImport(#"..\ref\myCApp.dll", CallingConvention = CallingConvention.StdCall)]
unsafe private static extern UInt16 ProcessFilesC(
String[] p_FilesOrDirs,
ref ImageInfoC[] p_vecImageInfo,
out Int32[] p_vecStackIndexes,
out RectC[] p_vecFaces
);
public unsafe struct ImageInfoC
{
public String resizedFilePath; //char* (in C)
public Byte isUsable; //unsigned char (in C)
public UInt32 imageId; //long int in (in C)
public UInt16 stackIndex; //int (in C)
public Boolean isBestPhoto; //unsigned char (in C)
}
Below is C# code to call the method
unsafe
{
iResult = ProcessFilesC(
p_FilesOrDirs, // Value getting passed to DLL
ref p_vecImageInfo,
out p_vecStackIndexes,
out p_vecFaces
);
Console.WriteLine("ProcessFilesC Complete");
}
When code reaches here, I can see that method is processing as it prints in console but after processing, it raises the mentioned exception.
I guess this is due to C DLL is trying to write values in output/ref parameters.
I am not getting where is the issue or what's the wrong in my code.
Please note that I have already uncheck option "Suppress JIT optimization on module load" at Tools -> Options -> Debugging -> General
Please help as soon as poosible.
Thanks for spending to valuable time to read this post.
Thanks,
Kiran
The first thing to check is the calling convention. In most cases the calling convention specified in your DllImport attribute differs from the actual calling convention in the native DLL.

dll C# AccessViolationException

dll written in Delphi, according to the manual I have to first set the xml path by SET_XML(), then use any function you like.
Delphi functions according the manual:
function SET_XML(var path: PAnsiChar): LongInt;
function GET_CALCULATION_FAN_ALONE(var fanDescription: PAnsiChar): LongInt;
Use in VB according to the manual:
Public Declare Function SET_XML_PATH Lib "fan.dll" (ByRef path As String) As Long
Public Declare Function GET_CALCULATION_FAN_ALONE Lib "fan.dll" (ByRef path As String) As Long
Sub Main()
Dim a As Long, b As Long, Str_Result As String, Str_Input As String
Str_Input = "C:\Users\Sebastiaan\Documents\Visual Studio 2010\Projects\Lucam selectie\Lucam selectie\bin"
a = SET_XML_PATH(Str_Input)
Str_Result = "65464;;;1,2;;23;424,8;0,3766;;"
b = GET_CALCULATION_FAN_ALONE(Str_Result)
End Sub
I did rewrite it in C#
const string _dllLocation = "EbmPapstFan.dll";
[DllImport(_dllLocation)]
public static extern long SET_XML_PATH(ref String path);
[DllImport(_dllLocation)]
public static extern long GET_CALCULATION_FAN_ALONE(ref String fanDescription);
public Main()
{
String path = #"C:\Users\Sebastiaan\Documents\Visual Studio 2010\Projects\Lucam selectie\Lucam selectie\bin";
long a = SET_XML_PATH(ref path);
String fanDescription = "65464;;;1,2;;23;424,8;0,3766;;";
long c = GET_CALCULATION_FAN_ALONE(ref fanDescription);
}
When running de application I get an AccessViolationException
Attempt to read or write protected memory. This often indicates that other memory is corrupt.
When setting a breakpoint and debugging the code step by step nothing every thing rusn just fine. sometimes i got the error in the debug mode (on line "long c = GET_CALU...")
What am I doing wrong?
I'm not familiar with calling Delphi from C#, but from a quick search it appears that there are some issues with the calling conventions (how values are pushed and popped from the stack). See these threads:
Calling a Delphi DLL from C# produces unexpected results
Calling a delphi DLL method from C# Code
From these, it sounds like it may not be possible to call this directly due to the "fastcall" calling convention. You could try changing the calling convention, that could be worth a quick test. See this page:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention.aspx
If that doesn't work, I would probably just write a C wrapper DLL that calls the Delphi DLL, and verify that works (make sure it's not just a bug in the DLL). If it does, then you could just call the C DLL from the C# program by using DllImport on your wrapper DLL's function.
Hope that helps a bit,
John

Categories