Can't catch exception caused by C dll called via PInvoke - c#

I'm writing a C# .NET 3.5 program wich uses the latest MediaInfoLib Dll.
It seems that it causes an exception for some files.
I want to catch those exceptions and ensure my program continues running,
but for some reason I can't catch it with a simple try/catch statement.
PInvoke Methods:
[DllImport("MediaInfo.dll")]
private static extern IntPtr MediaInfo_New();
[DllImport("MediaInfo.dll")]
private static extern IntPtr MediaInfo_Open(IntPtr Handle,MarshalAs(UnmanagedType.LPWStr)] string FileName);
Usage:
Handle = MediaInfo_New();
try{
MediaInfo_Open(Handle, FileName)
} catch { }
Calling MediaInfo_Open(Handle, FileName) might cause an exception.
Instead of catching the error with the try/catch statement, my program exits and "vshost32-clr2.exe" crashes. (It also crashes as a release build and with no debugger attached)
After searching the web, I found someone who suggested to check "Enable unmanaged code debugging", which only resulted in my program exiting without vshost32-clr2.exe crashing.
Any idea how I can catch the exception?

If the unmanaged DLL is causing the crash (rather than just returning an error code of some kind), then there's no way to catch it. Once you've gone outside of the .NET runtime's control, it's entirely up to the unmanaged code; there's nothing the .NET runtime can do.

I've had a similar problem (with BSTR specifically) but hopefully this will help.
There is a bug in .NET (fixed in 4.0) when internally marshalling strings back from unmanaged code. More Info
The work-around is to change your P/Invoke signature to use an IntPtr and do the string marshalling yourself.
[DllImport("MediaInfo.dll", EntryPoint = "MediaInfo_Open")]
private static extern IntPtr _MediaInfo_Open(IntPtr handle, IntPtr filename);
internal static extern IntPtr MediaInfo_Open(IntPtr handle, string filename)
{
IntPtr stringPtr = Marshal.StringToBSTR(filename);
return _MediaInfo_Open(handle, stringPtr);
}

Related

UnmanagedFunctionPointer causes stackoverflow when using .NET 4.0, 3.5 works

I have a simple function inside of a click handler that has a try catch block. If I throw an exception within this try catch block it catches the exception successfully.
If I put a call to an unmanaged DLL before I throw the exception the exception is unhandled and not caught.
What is the unamanged DLL call doing that could be breaking my programs exception handling?
If I run the program in debug mode it catches the exception even with "break on exception" unticked for all exceptions. The application does not crash and runs as expected.
If I run the program as "start without debugging" and hit debug when it crashes I get the following error "Stack cookie instrumentation code detected a stack-based buffer overrun"
edit:
It appears the stack overflow breaks the exception handling
I've attached a simplified program that produces the crash.
ISOConnection _comm; //This is instantiated at another time in the same thread
//C# test function that crashes when run without a debugger attached
bool DoMagic()
{
try
{
//if I uncomment this line the exception becomes unhandled and cannot be caught
//_comm.ConnectISO15765();
throw new Exception();
}
catch (Exception ex)
{
MessageBox.Show("Caught exception")
}
//Within ISOConnection class
public void ConnectISO15765(){
...
lock(syncLock){
uint returnCode = J2534Interface.PassThruConnect((uint)DeviceId, (uint)ProtocolID.ISO15765, (uint)ConnectFlag.NONE, (uint)BaudRate.ISO15765, ref ChannelId);
//C# UnmanagedFunctionPointer allocation code
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId);
public PassThruConnect Connect;
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
m_pDll = NativeMethods.LoadLibrary(path);
...
pAddressOfFunctionToCall = NativeMethods.GetProcAddress(m_pDll, "PassThruConnect");
if (pAddressOfFunctionToCall != IntPtr.Zero)
Connect = (PassThruConnect)Marshal.GetDelegateForFunctionPointer(
pAddressOfFunctionToCall,
typeof(PassThruConnect));
//C++ function declaration
long PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID, unsigned long Flags, unsigned long Baudrate, unsigned long *pChannelID);
UPDATE
If I replace the call to the UnmanagedFunctionPointer PassThurConnect with the following the crash does NOT occur
[DllImport("op20pt32.dll", EntryPoint = "PassThruConnect", CallingConvention = CallingConvention.Cdecl)]
public static extern uint PassThruConnect2(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId);
Is there something I am not performing or I am performing incorrectly when assigning the UnmanagedFunctionPointer that would cause the lack of a debugger to create a stackoverflow crash?
What is even stranger is this code appeared to work a few weeks ago. The main changes is the try catch was in another thread and I wasn't using lock(syncLock). Everything is now in one thread however the same crash occurred when run in a BackgroundWorker as well.
UPDATE #2 PROBLEM SEMI-SOLVED
Ok so I rolled back through my commits one by one until it worked. What changed is I went from .NET 3.5 to .NET 4.0
.NET 3.5 does not crash regardless of attaching a debugger or not. .NET 4.0 crashes if a debugger is not attached. To rule out a bug in my code I simply deleted the ConcurrentQueue for my log (the only 4.0 feature I was using) and converted my current code base back to 3.5 and I do not get this error.
To be 100% sure it is an issue with 4.0 I then converted my code base back to 4.0 from 3.5 and left the ConcurrentQueue out (literally just changed the build options and did a rebuild) and the StackOverflow crash is back.
I would prefer to use 4.0, any ideas how to debug this issue?
edit: .NET 4.6.1 also crashes
UPDATE #3
http://codenition.blogspot.com.au/2010/05/pinvokestackimbalance-in-net-40i-beg.html
Apparently pinvokestackimbalance is basically ignored in .NET 3.5, so the problem still exists, it just doesn't crash my application.
Adding the following code to App.Config causes .NET to repair the stack when transitioning back to managed code. A small performance hit but it will fix the problem.
Whilst this does fix the problem, I'd like to know what is wrong with my UnmanagedFunctionPointer to cause the problem in the first place.
<configuration>
<runtime>
<NetFx40_PInvokeStackResilience enabled="1"/>
Edit: this thread isn't a duplicate, the other one is deleted...
Ok so the problem is the calling convention should be StdCall not Cdecl
This makes sense as the generic J2534 API documentation specifies the following header. Although the header file I was supplied does not make this specification.
extern "C" long WINAPI PassThruConnect
(
unsigned long ProtocolID;
unsigned long Flags
unsigned long *pChannelID
)
Where WINAPI is also known as StdCall not Cdecl like most C/C++ libraries would typically use.
.NET 3.5 allows the wrong calling convention and will "fix" the stack. As of 4.0 this is no longer the case and a PinvokeStackImbalance exception is raised.
You can force 4.0 to also fix the stack with the following code added to your App.Config
<configuration>
<runtime>
<NetFx40_PInvokeStackResilience enabled="1"/>
Or you can simply fix your calling convention by changing Cdecl to StdCall:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelID);

P/Invoke "Protected Memory" exception on /MT or /MD

I've coded a wrapper for CryptoPP which would be used by c# app.
My issue is that when calling to a specific function in my wrapper using PInvoke, throws an exception "Attempted to read or write protected memory...".
Both of them are compiled as x64.
Now.. strange part is that if i compile my wrapper using /MTd or /MDd runtime, the call does not fail and everything works perfectly. But changing the runtime to /MT or /MD would throw the above exception.
I cannot use the /MTd or /MDd option for official use by my customers, as it requires lots of dlls resources to be installed or distributed into the user machine.
cpp code:
extern "C" __declspec(dllexport) int CryptBlock(bool mode, unsigned char type, unsigned char *inData, unsigned char *outData, int dataLen, unsigned char *key, int keyLen);
c# PInvoke:
[DllImport("mydll.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int CryptBlock(bool mode, byte type, IntPtr inData, IntPtr outData, int dataLen, IntPtr key, int keyLen);
I have tried modifying my P/Invoke code in various ways:
[In, Out], [Out], ref, ref byte[], byte[] etc... still throwing the exception.
Waiting for my savior...
Thank you.
You are right that you cannot distribute the debug runtime, but in fact the issue is not quite what you think. The license does not permit redistribution of the debug runtime.
The most likely explanation is in fact that your code has a defect. The fact the the defect does not manifest with the debug runtime is simply down to chance. So the correct way to proceed is to track down your defect and fix it.
Consider using a bridge between Managed and Unmanaged code.
It can be debug more easily...
Example:
C++ Unmanaged code:
class ExampleCpp
{
private:
int id;
public:
ExampleCpp();
~ExampleCpp();
const int getId();
};
C++ Managed Code:
public ref class ExampleManagedCpp
{
private:
ExampleCpp* pImpl;
public:
ExampleManagedCpp();
~ExampleManagedCpp();
!ExampleManagedCpp();
};
http://www.codeproject.com/Articles/868230/Cplusplus-CLI-Accessing-a-managed-type-from-unmana
http://blogs.msdn.com/b/soultech/archive/2010/07/27/cli-c_2b002b00_-to-c_2300_-hello-world.aspx

C# - cc3260mt.dll throws ArithmeticException whenever I load it

I have a WPF Application, and I must load the DLL cc3260mt.dll
I call it by using LoadLibrary(), but for whatever reason I am getting an ArithmeticException.
Here is what my code looks like :
public partial class MainWindow : Window
{
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
static extern IntPtr FreeLibrary(IntPtr hModule);
public MainWindow()
{
InitializeComponent();
try
{
string cc3260mtPath = "dll/cc3260mt.dll";
IntPtr cc3260Link = LoadLibrary(cc3260mtPath);
}
catch (Exception ex)
{
Console.WriteLine("ERROR : " + ex.Message);
}
} // <-- This is where I get the Exception.
}
When I run my code step by step, I can clearly see that the exception appears when I get out of my MainWindow() class.
Do you guys have any idea what gets me this exception ?
That is the C runtime support library for old Borland C or C++ programs. And yes, it does something that's very incompatible with .NET code in general, and WPF in particular, it reprograms the floating point unit control register. It enables hardware exceptions, triggered when a floating point operation fails. Particularly problematic in WPF because is likes to use Double.NaN a lot. Which generates an FPU exception, the CLR intercepts it and re-raises it as an ArithmeticException.
You will have to undo what this DLL did and restore the FPU control word. This is problematic, .NET doesn't give you direct access to the hardware like that. There is however a trick you can use, the CLR automatically reprograms the FPU when it handles an exception. So you can intentionally generate an exception and catch it. Like this:
IntPtr cc3260Link = LoadLibrary(cc3260mtPath);
try { throw new Exception("Ignore this please, resetting the FPU"); }
catch (Exception ex) {}
Do note the consequence of this, you'll now have the native code running without the exceptions it normally relies on. Maybe that will work.

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.

PInvoke: Error in returing text from C++ to C#

I am using Pinvoke for Interoperability between Native(C++) code and Managed(C#) code. What i want to achieve is get some text from native code into my managed code as a retrun value i.e My C# Code calls my C++ function which returns some text back to C#. Following is my code for this.
C++ Code:
static std::wstring WSTR_TEMP;
wchar_t* cppReturnSomeText()
{
UnicodeString usText ("Some Text Here");
WSTR_TEMP = ECUtilsICU::UniCodeStringToWString(usText);
return (wchar_t *)(WSTR_TEMP.c_str());
}
C# Code:
[DllImport(MY_DLL_NAME]
[return: MarshalAs(UnmanagedType.LPWStr)]
private static extern string cppReturnSomeText();
public static string GetSomeText()
{
string s = cppReturnSomeText();
return s;
}
Every thing was working fine as expected. Now i simply change my operating system from WinXP(32Bit) to Win7(64Bit). And when i run this code following error occurred:
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I guess the problem is that you are allocating memory with your C++ runtime's allocator but then the C# marshaller attempts to deallocate it. That cannot work. You need to allocate and deallocate with the same allocator.
The best way I know to solve your problem is to marshal with a BSTR. That uses the COM allocator which is happy to be shared between native and managed modules.
#include <comutil.h>
BSTR cppReturnSomeText()
{
UnicodeString usText("Some Text Here");
std::wstring result = ECUtilsICU::UniCodeStringToWString(usText);
return ::SysAllocString(result.c_str());
}
On the C# side you do this:
[DllImport(MY_DLL_NAME, CallingConvention=CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string cppReturnSomeText();
One other benefit of this is that your code is now thread-safe because you no longer need a global variable.

Categories

Resources