Pinning a Structure to avoid AccessViolationException - c#

I am calling an function from a DLL which is loaded run-time (Using LoadLibrary()).
This DLL is written in C++ and my code is in C#.
API requires Structure Pointer. I am passing "ref" instead of Pointer.
While doing this, I getting "AccessViolationException". After 3 days of Googling, I think the problem could be solved by Pinning the Structure so that GC won't disturb it.
(See: Passing struct by reference causing AccessViolationException)
My question is Can I pin a structure without using any Pointers? Because I don't want to pass a pointer to function.
Code is as follows:
public class TestClass
{
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi)]
public struct MsgFormat
{
public Int32 MsgID;
public Int32 RxID;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=13)]
public Char[] MsgData;
}
unsafe public delegate Int32 ReadMessage(Int32 ConnectID,ref MsgFormat Message);
ReadMessage fp_ReadMessage;
void Connection()
{
IntPtr pDLLHandle;
pDLLHandle=LoadLibrary(Connect.dll); // Load Required DLL
IntPtr fPtr= GetProcAddress(pDLLHandle,"ReadMessage");
fp_ReadMessage=(ReadMessage)Marshal.GetDelegateForFunctionPointer(fPtr,typeof(ReadMessage)); // Get Function Pointer for API
}
void Read()
{
MsgFormat Rx_Msg=new MsgFormat();
Int32 nReturnValue;
Int32 nConnectID=0; // Value is assigned for Testing the Function
/* Also Tried:
Rx_Msg.MsgData=new Char[13]; */
nReturnValue= fp_ReadMessage(nConnectID,ref Rx_Msg); // "ReadMessage" will return info in Rx_Msg;
/* Call to fp_ReadMessage gives me "AccessViolationException". I have tried making that Ref to IntPtr even Passed IntPtr.Zero Still I am getting the error */
}
}
}
Regards,
Swanand!

I don't think pinning will help you here. The CLR will ensure that any parameters you pass to an interop call don't move in memory until the call returns.
So the only situation when you need to do some manual pinning is if the function you call stores the pointer and writes to it later.
To know why you get an access violation, we need more information about the native function you're calling (like the function signature).

Related

Crash when passing an UnmanagedCallersOnly function pointer to C++ via P/Invoke call decorated with SuppressGCTransition

Suppose we have the following C++ code:
typedef int (*getIntPtr)(void);
extern "C" __declspec(dllexport) void InvokeFuncPtr(getIntPtr funcPtr) {
std::wcout << funcPtr();
}
We can match this definition in C#:
[DllImport("NativeLib.dll", CallingConvention = CallingConvention.Cdecl), SuppressGCTransition]
public static unsafe extern void InvokeFuncPtr(delegate* unmanaged[Cdecl]<int> funcPtr);
And then we can use this function like so:
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
public static int ReturnInt() => 123;
// ... Elsewhere:
unsafe {
InvokeFuncPtr(&ReturnInt);
}
When InvokeFuncPtr is marked with SuppressGCTransition this results in the program crashing with the error "Fatal error. Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code.". If we remove the SuppressGCTransition attribute it works as expected, and 123 is printed to the console.
Is this expected behaviour? I imagine it amounts to the runtime seeing ReturnInt() as being invoked from managed code, simply with a couple of extra steps of indirection. If so, is there any way around this, or should I simply leave the SuppressGCTransition attribute off?
Yes, you should leave off SuppressGCTransition, as the stack is what the runtime uses to identify whether the caller is managed or unmanaged.
If there is no transition in the stack, there is no way for the runtime to tell that the stack transitioned to unmanaged.
Alternatively, you can leave off UnmanagedCallersOnly, and instead marshal the delegate with Marshal.GetFunctionPointerForDelegate.

Shared memory between C++ DLL and C# code

I am currently working on a project with really short deadline, so I don't have much time to understand everything. Also, I am not an expert in C++ development and memory management.
So, what I am trying to do is to create a DLL in with both C and C++ code. Then, I would like to call this DLL in a C# code. Currently, the communication between C++ and C# is OK. The problem comes up when I try to transfer a string from the DLL to the C# code. The error is this one :
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
at NMSPRecognitionWrapper.Program.<Main>b__0() in <my dir>\Program.cs:line 54
at NMSPRecognitionWrapper.Program.StartRecognitionExt()
at NMSPRecognitionWrapper.Program.Main(String[] args) in <my dir>\Program.cs:line 60
Also, I can give you some piece of code below (really simplified !). Actually, the C++ expose two methods : StartRecognition() launch operations to get some data from microphone, then process them and store the results. GetResults() return an instance of the results previously stored. The WrapperCallback() allows the C# part to be called when a Result is able for processing. The C# part, when the Callback is called, will ask to get the results using the GetResults() method.
I know the architecture may seem really inappropriate in this presentation, but I don't want to explain the whole project to validate the model, please be sure everything is correct.
To finish, the problem is when the C# callback call the GetResults() method. Trying to access to the resultsForCS seems to be impossible from the C#.
C++ part - header
// NMSPRecognitionLib.h
#pragma once
#include <iostream>
using namespace std;
extern "C" __declspec(dllexport) char* GetResults();
extern "C" static void DoWork();
extern "C" __declspec(dllexport) void StartRecognition();
C++ part - sources
#include "stdafx.h"
#include "NMSPRecognitionLib.h"
static char * resultsForCS;
static SUCCESS ProcessResult(NMSPCONNECTION_OBJECTS *pNmspConnectionObjects, LH_OBJECT hResult)
{
[...]
char* szResult;
[...]
resultsForCS = szResult;
DoWork();
[...]
return Success;
error:
return Failure;
} /* End of ProcessResult */
extern "C" __declspec(dllexport) char* GetResults()
{
return resultsForCS;
}
extern "C"
{
typedef void (*callback_function)();
callback_function gCBF;
__declspec(dllexport) void WrapperCallback(callback_function callback) {
gCBF = callback;
}
static void DoWork() {
gCBF();
}
}
extern "C" __declspec(dllexport) void StartRecognition()
{
char* argv[] = { "path", "params" };
entryPoint(2, argv);
}
C# part
class Program
{
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetResultsExt();
public delegate void message_callback_delegate();
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "WrapperCallback")]
public static extern void WrapperCallbackExt(message_callback_delegate callback);
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "StartRecognition")]
public static extern void StartRecognitionExt();
static void Main(string[] args)
{
WrapperCallbackExt(
delegate()
{
Console.WriteLine(GetResultsExt());
}
);
StartRecognitionExt();
Console.WriteLine("\nPress any key to finish... ");
var nothing = Console.ReadLine();
}
}
I understand that the problem comes because I am using a pointer to store the results (char *), but I actually don't know how to do this in another way. The szResults type is char * too and I can't change this !
Yes, the return type is the problem. The pinvoke marshaller must do something to release the memory that was allocated for the string. The contract is that memory allocations that need to be released by the caller must be allocated from the COM heap. CoTaskMemAlloc() in native code, also exposed in .NET as Marshal.AllocCoTaskMem().
This rarely comes to a good end, most native code allocates with malloc() or ::operator new, allocating from a heap that's created by the C runtime library. The wrong heap. So inevitably the CoTaskMemFree() call will fail. Ignored silently in Windows XP and earlier, a kaboom on Vista and up.
You must stop the pinvoke marshaller from trying to release the memory. Do so by declaring the return value as IntPtr. And use Marshal.PtrToStringAnsi() to recover the string.
You still have a Big Problem, the kind of problem that bedevils any native code that tries to use this function as well. You still have a string buffer that needs to be released. You cannot do that from C#, you can't pinvoke the correct version of free() or ::operator delete. A memory leak is inevitable. The only thing you can hope for is that the native code takes care of it, somehow. If it doesn't then you must use C++/CLI to interop with it. With the additional requirement that the native code needs to be rebuilt with the same compiler so that it uses the same shared CRT. Code that's difficult to use correctly from native code is also hard to pinvoke. That's a design flaw, always allow the caller to pass a buffer to be filled in so there's never a question who owns the memory.
Looking at:
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
I can see that your callback is called, but the runtime tries to free some memory. I think it assumes your pointer would be to com memory. Try converting the string yourself, it is easy!
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
public static extern IntPtr GetResultsExt();
[...]
string result = Marshal.PtrToStringAnsi(GetResultsExt())
No 100% guarantee, but worth a try.
I have found that it is usually easier to write a wrapper in C++/CLI around the C++ native code. A C++/CLI class can directly call and use native C++, but is accessible from C# (and any .Net language). In my experience, using DLLImport as you do leads to hard to debug and find errors.

set C++ function pointer as C# delegate

I have a unmanaged c++ application as COM client and a C# COM server.
now i want COM server can invoke a c++ function.
C# :
[ClassInterface(ClassInterfaceType.AutoDual)]
public class SomeType
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DeleCallBack(string info);
public DeleCallBack CallBack;
public void SetCallBack(ref IntPtr ptr)
{
CallBack = (DeleCallBack)Marshal.GetDelegateForFunctionPointer(ptr, typeof(DeleCallBack));
}
}
C++:
HRESULT hr = E_FAIL;
CComPtr<WindowsFormsApplicationVC9::_SomeType> spTmp;
hr = spTmp.CoCreateInstance(__uuidof(WindowsFormsApplicationVC9::SomeType));
if (SUCCEEDED(hr))
{
spTmp->SetCallBack(OnCallBack);
}
void OnCallBack(BSTR info)
{
// c++ function call...;
}
I'm not sure it is the right way to just pass the OnCallBack function pointer to SetCallBack.
I noticed that some sample of calling GetDelegateForFunctionPointer should GetProcessAddress to get the function pointer address, but i can't do that since there are may be different c++ COM client with different function name.
any suggestion?
One way to do it is to expose your C++ functions via __declspec(dllexport), then simply write P/Invoke for those functions. Now you can use those P/Invoke functions as delegates.
Deep down this is essentially the GetProcAddress approach but the C# compiler makes it syntactically nicer for you.

Error calling an unmanaged windows DLL from a C# WPF application

I am working on a project that requires implementing am unmanaged windows DLL. The DLL is used to communicate with a USB device. My code is in C# and WPF.
To initialize the DLL I call a function called:
InitTimerDll(Int32 wHandle, ref dllInitParams initParams);
When calling this function I have to pass a struct called dllInitParams and the Handle that the control is bound to.
I am using DllImport for function pointer as such:
[DllImport("myDll.dll")]
public static extern void InitTimerDll(Int32 wHandle, ref dllInitParams initParams);
Here is my struct:
public struct dllInitParams
{
public UInt16 simp;
public UInt16 simt;
}
All of the above are in a separate class called myDllInterface.cs. Here is how I call the InitTimerDll function from my WPF form:
public IntPtr Handle
{
get { return (new System.Windows.Interop.WindowInteropHelper(this)).Handle; }
}
private void initTime_Click(object sender, RoutedEventArgs e)
{
myDllInterface.dllInitParams initParams = new myDllInterface.dllInitParams();
initParams.simp = 0;
myDllInterface.InitTimerDll(this.Handle.ToInt32(), ref initParams);
}
The first part of the above code explains how I get the handle and the initTime_Click shows how I initialize the struct, call the initTimeDll function by passing the handle and the struct to it. I have copied the dll file in the directory that the code runs in. My code compiles just fine but it creates an error when I click on the initTime button.
Error:
An unhandled exception of type 'System.AccessViolationException' occurred in ProbeCTRL.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Why is this happening?
Without knowing exactly what the InitTimerDll() function does with the 'this' pointer, I would focus on the params structure. Try adding a structure layout markup like the following:
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct dllInitParams
{
public UInt16 simp;
public UInt16 simt;
}
Also, double check that your structure is complete and accurate.
I found the problem. The code is fine the problem was the dll file, which was corrupted. A proper copy of the dll file took care of the problem. When using dll in your codes it is quite important to make sure you have accurate information, function calls, data types to passed and so on.
Thanks everyone for your help.
Have a look at the PInvoke tutorial: http://msdn.microsoft.com/en-us/library/aa288468%28v=vs.71%29.aspx
as Jim Gomes points out:
[StructLayout(LayoutKind.Sequential)]
or something similar is definitely important.
Also, you're only initializing one of the variables in your struct.

Error in my calling Function

this is my code
public delegate void NotifyFunc(enumType notificationType, IntPtr data);
[DllImport("VssSdkd")]
public static extern void startVssSdkClientEcho(string IpAddress,
long port, NotifyFunc notifyFunc, eProtocolType proType, bool Req);
am call the function like
CallBack calbck = new CallBack(TestDllImport.Callbackas);
startVssSdkClientEcho("192.168.10.240", 12050, calbck, TestDllImport.eProtocolType.eProtocolType_VssSdk, false);
here my receving callback function is
static public void Callbackas(eNotificationType type, IntPtr datas) {}
here first time am receving data and then it's giving Error msg like :
run time check failure #0 - the value if ESP was not properly saved across a function call.
this is usually a result of calling a function declared with one calling convention
with a function pointer declared with a different calling convention
please help me to identify my error... thanks in advance
Is this your code you are calling (sorry cursory search could only find your other post referring to startVssSdkClientEcho). Is it decalred cdecl (i.e. it has no __declspec at all) or is it stdcall. If it is cdecl you need to add CallingConvention attribute to the DllImport
i.e.
[DllImport("VssSdkd", CallingConvention=CallingConvention.Cdecl)]
Of course it might also be the callback calling convention at fault which is another issue.

Categories

Resources