❔ Problem with including C DLL in a C# console app project.
So I have this C DLL imported into my console app (.NET 5). I simply cannot get to call it correctly, since everytime I get, something along the lines, that something with the entrypoint is broken, like:
System.EntryPointNotFoundException: 'Unable to find an entry point named 'getCalculatedFitting' in DLL 'BPCalculationDLL.dll'.'
The code with which I am defining this is
[DllImport("BPCalculationDLL.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getCalculatedFitting")]
public static extern int getCalculatedFitting(float[] fittinglData, uint length, char ch);
Honestly I tried a few things, but none of them seem to work in the current VS2022 editor. Does anyone have any idea how import this DLL and call it in another function?60 Replies
use dll viewer or dependency walker and check the exported symbols
It looks like it is a C++ function after all.
So what to include in the DLL import tag?
Looks like nothing has happened here. I will mark this as stale and this post will be archived until there is new activity.
Ok, I managed to get to work, but I am getting a
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
The function i tried to import is something along the lines
//private static extern int calculateBP(ushort[] data, uint len, char ch, uint samplingRate, IntPtr results);
or
//private static extern int calculateBP(out ushort[] data, uint len, char ch, uint samplingRate, IntPtr results);
//private static extern int calculateBP(ref ushort[] data, uint len, char ch, uint samplingRate, ref Measurement[] results);
defined as
int CalculateBP(USHORT * data, UINT len, UCHAR ch, UINT samplingRate, measurement * results);
I triend numerous things, including to allocate some memmory using marshal, but still no luck. Any idea how to debug and solve this. The measurement
struct contains a number of floats
and integers
which I have also defined, but apparently I can't call it correctly.it would help to see both the C++ function signature and struct definition and C# struct definition and marshalling code
first thing i see is your data types are probably wrong and i don't believe
[DllImport]
automatically marshals arrays for youThe C++ function as defined in the header file is the following:
__declspec(dllexport) int CalculateBP(USHORT * data, UINT len, UCHAR ch, UINT samplingRate, measurement * results);
while the DLL import is the following:
[DllImport("BPCalculationDLL.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?CalculateBP@@YAHPAGIEIPAUmeasurement@@@Z")]
The C is defined by typedef struct{
float val1;
float val2;
int numBettween;
int error;
} measurement;
I meant by marshaling is that is tried to use methods to deal with unmanaged code (from the System.Runtime.InteropServices.Marshal
namespace), but to no success. I also trie some combinations mentioned on SO (https://stackoverflow.com/questions/28595903/copy-from-intptr-16-bit-array-to-managed-ushort), but no success.Stack Overflow
Copy from IntPtr (16 bit) array to managed ushort
I have a IntPtr called rawbits, which points to a 10MB array of data, 16 bit values. I need to return a managed ushort array from that. The following code works but there is an extra BlockCopy I wo...
not just the dllimport attribute, the whole method signature
so as I defined it in C#?
right
first thing is C++ chars aren't the same as C# chars, the former is 1 byte and the second is 2 bytes
I tried multiple approaches with multiple combinations, but none of the seem to give the desired result
second you can't pass arrays to unmanaged code like that, the GC could move them while the unmanaged code is trying to work with them and that would be Bad
they have to be pinned
if you use the new-ish
LibraryImport
attribute instead of DllImport
it can generate that code for youoh, I understand
How exactly do I do that?
it's more or less just replacing the attribute
P/Invoke source generation
Learn about compile-time source generation for platform invokes in .NET.
oh, nevermind
is this something in .net 7 only?
yeah
ok
then I need first to upgrade to .net 7 from 5
if you can you might as well
if not you can hand-write the same code that
LibraryImport
would generateok, so now i have this
an 3 errors
You need to specify which parameter is used for the array's size @šanji
like that?
[MarshalAs(unmanagedType: UnmanagedType.LPArray)] ushort[] data
No like,
[MarshalAs(SizeParamIndex=1)] ushort[] data
iirc default marshaling for arrays is already LPArray,ok, so i am actuall more lost that I was before
😅
Okay, SizeParamIndex just specifies that the parameter index we'll use to indicate the length of the array data is at position
1
which is uint lenthis just gives me an error
oops sorry
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
no problem
So i just need to figure out this
nevermin, it's a byte
ok...I think I got it.
private static partial int calculateBP([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ushort[] data, uint len, [MarshalAs(UnmanagedType.U1)] byte ch, uint samplingRate, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] Measurement[] results);
So now just need to pass in the neccessarry data and any empty measurement array of structs and I am golden? Do I need to worry if that the data is processed by other functions of the DLL and then that data can be corrupt?
Ok, I definitely need to think deeper, since I get invalid measurement results out of the function, and also other functions return invalid data.Can you show your C++ definition?
I guess you've already sent it
I think you're misunderstanding what passing an array by ref means
passing an array by ref is basically passing a pointer to the array
ref int[]
is the equivalent of int**
in C/C++yeah I just would like to finally solve this issue. Although I fixed the DLL importing issue, I probably just too plug in different numbers
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.Ok, so it seems that I magnaged VS no to crash on the call of the function, but something just doesn't seem right since i don't get the expected values in other functions
Hmmm, Are you still passing ref arrays?
getCalculatedFittingSize(UCHAR ch)
is always returning zero, but anything above should be the result. The c# call is th following. private static partial int getCalculatedFittingSize([MarshalAs(UnmanagedType.U1)] byte cuffNumber);
so now I am having the the function defined as private static partial int CalculateBP([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] ushort[] data, uint len, [MarshalAs(UnmanagedType.U1)] byte cuffNumber, uint samplingRate, ref Measurement result);
and calling it as CalculateBP(dataToUShort, (uint)dataToUShort.Length, 0, samplingRate, ref result);
Okay, first are you 100% sure the C++ method produces the correct results?
yes, the same underlying code is used else where, so i am sure it is my C# code, not the C++ code.
Can you show your
Measurement
struct?
Both C# and C++the c++ struct is here https://discord.com/channels/143867839282020352/1090377331970949250/1091780654854840512
and C# stuct is
[StructLayout(LayoutKind.Sequential)]
public struct Measurement
{
[MarshalAs(UnmanagedType.R4)]
float sys;
[MarshalAs(UnmanagedType.R4)]
float dia;
[MarshalAs(UnmanagedType.R4)]
float max;
[MarshalAs(UnmanagedType.R4)]
float amp;
[MarshalAs(UnmanagedType.R4)]
float hr;
[MarshalAs(UnmanagedType.I4)]
int maxIdx;
[MarshalAs(UnmanagedType.I4)]
int err;
}
which fields have wrong values?
based on the c++ logic (which is not documented I can't say for sure, but since the
int err
is always zero, the values do not break the code or result in an errorUnfortunately that's not how it'll work
Because your struct is different from this
This struct's error is at offset 0xC
Meanwhile your 0xC offset is for
amp
The offsets are basically like this
yeah, my mistake...I was truncationg it,just to write minimum code
the C# fields are present in C++ also
Huh, so
CalculateBP
should run okay thenso basically my values are messed up?
I honestly don't see what could fail, if you have the access to the source code you could step into it and see what happens after marshaling
is there a way to debug this DLL code? I mean like calling it from C#
Assuming you're using visual studio you just have to enable this on your launch profile
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.Ok, so managed to get it to work, but after a few files have been successfully processed, I just a NullReferenceException and an Unable ro read memory in the "Watch" tab for the needed array. My guess is that i ran out of addressable memory. How to overcome that?
Why are you assuming you're running out of addressable memory? 😅
Because I can easily process a few files without any issues
First I thought a file was corrupt, but then I tried out a new, independent set of files
Apparently it is the last file that is being processed and the last data structure in this file.
Unknown User•2y ago
Message Not Public
Sign In & Join Server To View
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.