PInvoke Array Marshalling Failure - c#

I have the following C++ function exported in a DLL:
extern "C" __declspec(dllexport) bool GetResolutionArray(int32_t adapterIndex, int32_t outputIndex, uint32_t arrayLength, Resolution outResolutionArr[]) {
memcpy_s(
outResolutionArr,
sizeof(Resolution) * arrayLength,
RENDER_COMPONENT.GetResolutionArray(adapterIndex, outputIndex),
RENDER_COMPONENT.GetOutput(adapterIndex, outputIndex).NumResolutions * sizeof(Resolution)
);
return true;
}
And, the matching extern function declaration in C#:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetResolutionArray", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetResolutionArray(int adapterIndex, int outputIndex, uint resolutionArrayLength, [MarshalAs(UnmanagedType.LPArray), In, Out] ref Resolution[] resolutions);
However, when I attempt to use this function as below, the program crashes with a FatalExecutionEngineError (indicating I corrupted something somewhere I guess) (error code 0xc0000005, i.e. access violation):
Resolution[] resolutions = new Resolution[outOutputDesc.NumResolutions];
if (!_GetResolutionArray(outAdapterDesc.AdapterIndex, outOutputDesc.OutputIndex, (uint) resolutions.Length, ref resolutions)) {
EnginePipeline.TerminateWithError("Internal engine call failed: _GetResolutionArray");
}
I strongly suspect that my call to memcpy_s is causing the access violation, but I can't see how or why, and I therefore reason that perhaps the marshalling is going wrong somewhere.
Thank you.

The array parameter is declared incorrectly. A C# array is already a reference and so you don't need the ref. Declare it like this:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetResolutionArray",
CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetResolutionArray(int adapterIndex,
int outputIndex, uint resolutionArrayLength, Resolution[] resolutions);

Related

calling c++ char* from c# project System.AccessViolationException

I'm trying to call a c++ library method from a c# project without much success. I always get the same error.
System.AccessViolationException: 'Attempted to read or write protected
memory. This is often an indication that other memory is corrupt.'
The c++ method signature looks like this
int __stdcall getErrorMessage(int errorId, char *&errorMessage);
I have tried every combination so far but nothing seems to work.
[DllImportAttribute("Lib.dll", EntryPoint = "getErrorMessage",
CallingConvention = CallingConvention.StdCall)]
public static extern int getErrorMessage(int errorId, ref StringBuilder errorMessage);
[DllImportAttribute("Lib.dll", EntryPoint = "getErrorMessage",
CallingConvention = CallingConvention.StdCall)]
public static extern int getErrorMessage(int errorId, ref IntPtr errorMessage);
[DllImportAttribute("Lib.dll", EntryPoint = "getErrorMessage",
CallingConvention = CallingConvention.StdCall)]
public static extern int getErrorMessage(int errorId, IntPtr errorMessage);
Any help will be really appreciated.
EDIT
The way Im calling it is as follows
var ptr = new IntPtr();
var ret = NativeMethods.getErrorMessage(number, ref ptr);
Also there is another call to release the memory once it's done
After you got IntPtr you should convert it to string using PtrToStringAuto Or PtrToStringAnsi
It's finally working, the problem happens as Hans Passant mentioned, when we try to query the method with any arbitrary error code.
Working code.
var ptr = new IntPtr();
var ret = NativeMethods.getErrorMessage(code, ref ptr);
if (ptr != IntPtr.Zero)
{
message = Marshal.PtrToStringAnsi(ptr);
NativeMethods.freePointer(ref ptr);
}
Thanks for your help.

Attempted to read or write protected memory with dllimport in c#

I have a problem with my project:
In dll c++:
extern "C" __declspec(dllexport) int results(char* imgInput, void* tree)
{
struct kd_node* nodeTree = new(tree)kd_node ; // new kd_tree with data from memory address
...
...
int ret = atoi(retValueStr.c_str());
return ret;
}
extern "C" __declspec(dllexport) void* buildKDTree(char* folder)
{
struct kd_node* kd_root;
....
feature *LFData = listFeat.data();
kd_root = kdtree_build(LFData,listFeat.size());
void* address_kdtree = (void*)&kd_root; // get memory address of kd_tree
return address_kdtree;
}
and I use to dllimport in c#:
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "buildKDTree", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern void* buildKDTree(byte[] urlImage);
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "results", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.I4)]
public unsafe static extern int results(byte[] imgInput, void* tree);
static unsafe void Main()
{
string urlImg1 = "C:/Users../test img/1202001T1.jpg";
string urlImg = "C:/export_features";
try
{
IntPtr result;
int result1;
result1 = results(convertStringToByte(urlImg1), 5, buildKDTree(convertStringToByte(urlImg))); // this error
Console.WriteLine("results = %d",result1);
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
}
when i run the program, this program show error :
Attempted to read or write protected memory. This is often an indication that other memory is corrupt
what error do you know and how to resolved ?
thank you!
You don't need a convertStringToByte method here. You can tell the runtime to marshal your string as a char *. Also, I would suggest that you make the method return an IntPtr, like this:
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "buildKDTree",
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr buildKDTree([MarshalAs(UnmanagedType.LPStr)]string urlImage);
[DllImport(#"kdtreeWithsift.dll", EntryPoint = "results",
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.I4)]
public static extern int results([MarshalAs(UnmanagedType.LPStr)]string imgInput, IntPtr tree);
You can then call it with:
IntPtr tree = buildKDTree(urlImg);
int result1 = results(urlImg, 50, tree);
Console.WriteLine("results = {0}",result1);
Well, for one thing, the C function is called buildKDTree, but you are importing it in the C# code with entry point "buildKDTreeWithFeatures". Try making these consistent and see if you get better results.
I try to call it :
IntPtr tree = buildKDTree(urlImg);
int result1 = results(urlImg, 50, tree);
Console.WriteLine("results = {0}",result1);
but it is not your fault where you said.
I think the variable intPtr tree in function results([MarshalAs(UnmanagedType.LPStr)]string imgInput, IntPtr tree); that caused the error
I think its similar problem due to char* parameters, in my own problem thanks to this below link question solves the problem.
So your only solution is to pass the string parameters as IntPtr.
Allocate the memory with Marshal.StringToHGlobalAnsi
Attempted to read or write protected memory with dllimport in c#

How to import void ** C++ API into C#?

In c++ API Declaration is
BOOL DCAMAPI dcam_attachbuffer ( HDCAM h, void** top, _DWORD size );
arguments :
void** top--- is the array of pointer to buffer
_DWORD size-- is size of top parameter in bytes
In c#, this is how I import the dll file:
[DllImport("dcamapi.dll", EntryPoint = "dcam_attachbuffer",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi, BestFitMapping = false,
ThrowOnUnmappableChar = true)]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
public static extern bool dcam_attachbuffer(IntPtr handleCamera,
[MarshalAsAttribute(UnmanagedType.LPArray)]ref Int32[] buf,
[MarshalAsAttribute(UnmanagedType.U4)] Int32 bufsize);
My question is do I convert the type from c++ into c# correctly? and How do I declare void**in c#? please help me.
It is depending on what function dcam_attachbuffer do.
If it's taking buffer, define method
[DllImport("dcamapi.dll", EntryPoint = "dcam_attachbuffer"]
public static extern bool dcam_attachbuffer(
IntPtr handleCamera,
IntPtr ptrsBuf,
Int32 bufSize);
and pass pointer derived earlier.
If function is getting pointer of pointers, define method
[DllImport("dcamapi.dll", EntryPoint = "dcam_attachbuffer"]
public static extern bool dcam_attachbuffer(
IntPtr handleCamera,
ref IntPtr ptrsBuf,
Int32 bufSize);
and use
System.Runtime.InteropServices.Marshal.Copy(
IntPtr source,
IntPtr[] destination,
int startIndex,
int length
)
to copy pointers in IntPtr[]
You can declare pointers directly in C# in unsafe blocks.
There's also IntPtr.
Or you can write some C++/CLI to glue the two together.
The argument is IntPtr[] (no ref). With the unnecessary attributes removed:
[DllImport("dcamapi.dll")]
public static extern bool dcam_attachbuffer(IntPtr handleCamera,
IntPtr[] buf, int bufsize);
Correctly initializing the array could be a challenge as well, it is quite unclear from the question what is required.

A Problem in Pinvoke

I have the following function in C++ native dll, and I want to use it in a C# app.
DWORD __cdecl Foo(
LPCTSTR Input,
TCHAR** Output,
DWORD Options,
ErroneousWord** List = NULL,
LPDWORD Count = 0
);
Using Pinvoke
[DllImport("dllName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 Foo(string InputWord, out string Output, UInt32 Options, out object List,out UInt32 Count);
Calling code:
string output;
object dummyError = null;
uint dummyCount = 0;
uint x = 0;
Foo(Text, out output, x | y,out dummyError,out dummyCount);
I got the following exception
Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt
P.S:
ErroneousWord is struct and I do not need its output, so I marshal it as object
That error more than likely means that you have a marshaling problem.
You don't show us what the ErroneousWord type is, but I assume it's some kind of class defined in your C++ code. My guess is that it's not being marshaled correctly to a .NET object.
Considering that it's a pointer (or a pointer to a pointer), try changing that parameter to an IntPtr type to represent a pointer, instead. It shouldn't matter, since you're simply passing NULL for the argument anyway, easily represented using the static IntPtr.Zero field.
You probably also want to marshal Output the exact same way. If you change the parameter to an IntPtr type, you'll receive a pointer to a TCHAR*, which you can then pass to the other unmanaged functions however you see fit (e.g., to free it).
Try the following code:
[
DllImport("dllName",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.Cdecl)
]
public static extern UInt32 Foo(
string InputWord,
out IntPtr Output, // change to IntPtr
UInt32 Options,
out IntPtr List, // change to IntPtr
out UInt32 Count);
IntPtr output;
IntPtr dummyError = IntPtr.Zero;
uint dummyCount = 0;
uint x = 0;
Foo(Text, out output, x | y, out dummyError, out dummyCount);
You might also need to use the Marshal.AllocHGlobal method to allocate unmanaged memory from your process that is accessible to the C++ code. Make sure that if you do so, you also call the corresponding Marshal.FreeHGlobal method to release the memory.
Given Cody's answer and the comments, you will have to do it this way:
[DllImport("dllName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
extern static UInt32 Foo(string InputWord, out IntPtr Output, UInt32 Options, out IntPtr List, out UInt32 Count);
Now to get the string value in Output marshalled over to managed memory you will do:
string outputValue = Marshal.PtrToStringAnsi(Output);
You must know if TCHAR is Ansi or Unicode and use the appropriate marshal.
Remember to hang onto the Output IntPtr so you can pass that to the native Free method.
Thanks Cody for your answer but I want to make a seperate one, first Output is created by Foo from the native side, and I call FreeFoo to free the allocated memory by Foo.
The following is the code
[DllImport("dllname", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 Correct(string InputWord, out IntPtr Output, UInt32 Options, out object List,out UInt32 Count);
[DllImport("dllname", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern void FreeFoo(IntPtr Output);
}
To use it:
public string FooWrapper(string Text)
{
IntPtr output;
object dummyError = null;
uint dummyCount = 0;
uint x = 0;
Foo(Text, out output, x,out dummyError,out dummyCount);
string str = Marshal.PtrToStringUni(output);
FreeFoo(output);
return str;
}
Whatever the ErroneousWord type is, you can't marshal an array as a single out object. If it is at all possible to marshal as an object...

Wrapper c# using unmanaged dll

I am making a wrapper to read TDM and TDMS files but i have a problem
[DllImport(lib, CharSet = CharSet.Auto)]
static extern int DDC_OpenFileEx(
[MarshalAs(UnmanagedType.LPStr)]
string filePath,
[MarshalAs(UnmanagedType.LPStr)]
string fileType,
int read_only,
ref long file);
works fine but
[DllImport(lib, CharSet = CharSet.Auto, SetLastError = true)]
static extern int DDC_GetNumChannelGroups(long file,
[MarshalAs(UnmanagedType.U4)]
ref int numChannelGroups);
int numGru = 0;
errCode = ReadTDM.DDC_GetNumChannelGroups(file,ref numGru);
System.Console.WriteLine("Error Code {0} GetNumChannelGroups", errCode);
gives an error -6202, // An invalid argument was passed to the library.
i have tried ref uint, uint * (unsafe), UIntPtr. The def from .h file
int __stdcall DDC_GetNumChannelGroups (DDCFileHandle file,unsigned int *numChannelGroups);
the second parametr is the problem.
it seems that unsigned int* != uint.
Does anyone have an idea how to call this function form the dll?
http://forums.ni.com/ni/board/message?board.id=60&thread.id=11821
It is the 1st argument that's declared wrong. That throws off the stack frame and prevents the unmanaged code from properly reading the pointer for the 2nd argument. "long" is 64-bits, DDCFileHandle is almost certainly a pointer, 32-bits on a 32-bit operating system.
Change the argument declaration to IntPtr. You'll also need to change the declaration of the function that returns that handle.

Categories

Resources