OK, so I have the C# DLL method:
public void DeletePublisher(string strName)
{
try
{
if (_PublisherData.PublisherDictionary.ContainsKey(strName))
_PublisherData.PublisherDictionary.Remove(strName);
}
catch (Exception ex)
{
SimpleLog.Log(ex);
}
}
It works fine. If there is a exception it is detected and added to the log.
At the moment, the above is called via MFC in my C++ project using a wrapper:
bool CMSATools::DeletePublisher(CString strPublisher)
{
bool bDeleted = false;
if (m_pInterface != nullptr)
{
CComBSTR bstrPublisher = strPublisher.AllocSysString();
throw_if_fail(m_pInterface->DeletePublisher(bstrPublisher));
bDeleted = true;
}
return bDeleted;
}
They both work fine. The issue is that fact that the CPP method currently has no knowledge of the C# method having failed. Now, in this particular instance I know I could change the signature of the DLL method to return false for a exception failure occurring and examine that return value in the CPP file.
But, in other instances I am already using the return value and thus, it would seem for consistency to me, that I pass in a bool bExceptionRaised parameter instead to my methods in the DLL.
That way, I can test that value when the method seemed to complete and if it is false act accordingly.
At the moment my application doesn't realise that an exception occurred and that is confusion.
Can I assume that either of these methodologies are the simplest approach to what I am trying to detect?
Update
Based on the answer provided I have tried to follow this tutorial and I am getting confused. I have tried to follow it and I can't create a CLR DLL and build it that is a bridge to my C# DLL file.
Whilst I appreciate the answer I feel like it is breaking up everything I have worked on since the C# DLL already handles and logs it's exceptions. Whilst I would like to learn how to build this bridge for the future, I still think perhaps at the point in time just changing my signatures is sufficient. Either way, my attempt a basic build of a bridge is failing.
Use a C++/CLI wrapper for the access of the managed component.
With C++/CLI you can directly use the C# component can catch the managed exception and you can throw a native exception or even return true or false... whatever you want.
void DoManagedStuff(SOMEDATA somedata)
{
try
{
auto sm = ConvertToSomeDataToManaged(somedata);
CallManagedCode(sm);
}
catch (Exception^ e)
{
throw CMyNativeException();
}
}
Related
I'm creating a C++ DLL to be used in C#. This DLL throws exceptions whenever anything is wrong and the idea is to handle these in the C# code.
I created a new exception class in C++ inheriting from std::runtime_error because I not only need the what but also a numeric ID:
class insight_exception: public std::runtime_error
{
public:
explicit insight_exception(const int id, const std::string message):
std::runtime_error(message), id{id}
{}
virtual ~insight_exception() noexcept {}
const int id;
};
Whenever something goes wrong in the C++ code I do this:
throw insight_exception(103, "size Pointer is NULL");
I have a little example in C# to "exercise" the DLL, just to test it before sending it to our C# developer, and when I execute the little C# program I can verify that the DLL is throwing the exceptions because I'm getting this:
terminate called after throwing an instance of 'insight_exception'
My problem is that I don't know any C# and I don't really know to "import" the insight_exception class into C# so I can catch it.
Solutions like this post don't help because they assume you can use the class by using a function like this:
insight_exception* create_insight_exception()
{
return new insight_exception();
}
And I can't do that because I need something like this in C#
try
{
}
catch (insight_exception e)
{
}
So I can't create the class like:
IntPtr insight_exception = create_insight_exception();
One important thing to know is that I'm creating the DLL on Linux by cross-compiling using MinGW, so I can't do #include <Windows.h> or any other windows-related includes or imports when creating the DLL. I don't really use Windows but only for my little test C# code.
EDIT:
Thanks to a comment, I looked into the following questions:
C# not catching unhandled exceptions from unmanaged C++ dll
This one looks promising but the problem is that the answer suggest a compilation done in Windows. I tried to add the /EHa compilation flag equivalent in GCC (-funwind-tables) but that doesn't help. I still can't catch the exception using catch (SEHException ex) nor catch (Exception ex) in the C# code.
Can you catch a native exception in C# code?
Suggests using Win32Exception but that doesn't work either. I can't catch the exception with catch (Win32Exception ex) in the C# code.
I'm creating a wrapper from loading 32-bit unmanaged dll to execute in 64-bit environment. so my approach used this LegacyWrapper
[LegacyDllImport("ste.dll")]
public interface INativeMethods : IDisposable
{
[LegacyDllMethod(CallingConvention = CallingConvention.Winapi)]
IIntPtr ste_init_with_environment_info(string dirLocation, string language);
}
I'm calling this method as below
public IWrapperConfig Configuration
{
get
{
return _configuration ??= WrapperConfigBuilder.Create().TargetArchitecture(TargetArchitecture.X86).Build();
}
}
using var client = WrapperProxyFactory<INativeMethods>.GetInstance(Configuration);
_steHandle = client.ste_init_with_environment_info(steHomeDirectory, SystemProperties());
it seems works without exception but. When I call the function, as a result, I'm getting 0x0000000000000000 which should be something like 0x0186ad58 what causes the issue?
UPDATE
when I see the source code of LagacyWrapper see the serialization and deserialization as below using System.Runtime.Serialization.IFormatter
public void SendCallRequest(CallData callData)
{
_formatter.Serialize(_pipe, callData);
}
public CallResult ReceiveCallResponse()
{
CallResult callResult = (CallResult)_formatter.Deserialize(_pipe);
if (callResult.Exception != null)
{
throw callResult.Exception;
}
return callResult;
}
I'm not very familiar with LegacyWrapper, so this is based on conjecture.
From the blogpost introducing Legacy wrapper:
Since we can’t load 32bit code into our 64bit process, the idea is to create a separate executable for this task. It would somehow load a library, invoke a specific function and pass the results back to the caller.
Since your library runs in another process, returning a pointer to memory will probably not work. As far as I know there is no general way to know how much valid memory a pointer points to, so how would the wrapper know how much memory to copy? This might be possible to solve for some special cases, but I cannot find any documentation about the details of the serialization-process.
You might be able to define that the pointer should be marshalled to a structure. Otherwise you might want to post an issue at the legacyWrapper project page, to clarify the documentation if nothing else.
In a Monodroid project, I need to be able to call a private method on a class. From an answer on a related question, it seems that this is possible in Java via reflection:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.os.ParcelFileDescriptor;
...
ParcelFileDescriptor pipe[] = null;
try {
Method createPipeMethod = ParcelFileDescriptor.class.getDeclaredMethod("createPipe");
pipe = (ParcelFileDescriptor[]) createPipeMethod.invoke(null);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
I need to use this code from Monodroid. Unfortunately, java.lang.reflect is not available in Monodroid. However, it has been suggested that I can run this code using JNI from my Monodroid project. The Xamarin documentation states that inline JNI is possible, without having to bind a whole JAR. Unfortunately, further documentation doesn't say anything more on the subject. Furthermore, the documentation on JNIEnv is blank.
It looks like I need JNIEnv.CallVoidMethod(), but I have no idea how to do it. I can't find an example, or further documentation.
How can I use java.lang.reflect in my Monodroid project, or in some other way call the private method .createPipe on ParcelFileDescriptor?
Did you try to use C# reflection on Android.OS.ParcelFileDescriptor?
http://docs.mono-android.net/index.aspx?link=T%3AAndroid.OS.ParcelFileDescriptor
I did not yet try it, but if Mono for Android even wraps private members of a Java class, simply using C# reflection might be enough.
If this failed, you can pursue on the JNI attempt.
It should be possible with JNI: http://docs.xamarin.com/guides/android/advanced_topics/java_integration_overview/working_with_jni#_Static_Methods
A rough untested sketch:
var methodId = JNIEnv.GetStaticMethodID(ParcelFileDescriptor.Class.Handle,
"createPipe",
"()[Landroid/os/ParcelFileDescriptor;");
var result = JNIEnv.CallStaticObjectMethod(myCSharpFileDescriptorInstance.Handle,
methodId);
i am having a problem with a ActiveX i am using via COM-Interop. it`s throwing an exception after i exit my Application and i am not sure if this is my fault or the fault of the ActiveX.
is the the correct way to initilize and release an ActiveX via COM-Interop?
Error Message
Sample Code which triggers the Exception
public void CreateInvoice()
{
String path = #"";
FaktNT.OLESrvClass OLESrv = null;
try
{
OLESrv = new FaktNT.OLESrvClass();
if (OLESrv.MandantLogin2() == 0)
{
try
{
//Do Stuff
}
catch (System.Exception ex)
{
//Log Error
throw;
}
finally
{
OLESrv.MandantLogout();
}
}
else
{
//Do Stuff
};
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(OLESrv);
OLESrv = null;
GC.Collect();
}
}
You should not need to release the COM object manually using Marshal.ReleaseComObject(). This is done by .net automatically (depending on what you are doing to the reference counting in the native COM code of course).
I would also try to check if the problem originates on the native side (for example in a destructor, which is called when the object is garbage collected).
Is the COM dll generating any native threads, which may be running after the object was garbage collected?
This is not a .NET message, the component itself is trapping the access violation exception. Looks like it was written in Delphi, judging from the exception name. Making native code bomb on an AV doesn't usually require a lot of help. But sure, you may be using the component 'incorrectly'. You stubbed out too much code to really make an informed guess. Other than that making calls on it in a finally block after you caught all exceptions that it might raise is a Bad Idea.
Getting it to bomb on program exit instead of after the GC.Collect() call is not healthy either. Sure sign that you haven't managed to call ReleaseComObject and null all the interface references. That's common, better to leave it up to the garbage collector to do it right. Albeit that this message box is going to bomb the finalizer thread. Yes, you probably need the vendor's help if a thorough code review doesn't help.
i solved the problem now. it was in fact me misusing the COM-Object, i missed to call OLESrv.EngineClose() which closes the COM-Object cleanly.
somehow this little piece of important informationen didn`t make it into the vendors documentation ...
This application has a WCF web service that is called by a WinForms app. The WinForms app has a class WCFCache to manage data from the service. There is a section like this in that class to manage an optional custom configuration section that a subset of the machines have:
private bool? m_HasCustomConfiguration = null;
public bool HasCustomConfiguration
{
get
{
if (m_HasCustomConfiguration == null)
m_HasCustomConfiguration = (CustomConfiguration != null);
return (bool)m_HasCustomConfiguration;
}
}
private WCFService.CustomConfiguration m_CustomConfiguration = null;
public WCFService.CustomConfiguration CustomConfiguration
{
get
{
if (m_CustomConfiguration == null)
{
if (m_HasCustomConfiguration.HasValue
&& !m_HasCustomConfiguration.Value)
return null;
try
{
using (WCFService.WCFServiceClient wcf = new WCFService.WCFServiceClient())
{
m_CustomConfiguration =
wcf.GetCustomConfiguration(Machine.ProcessID);
// Above method returns null if no record exists.
m_HasCustomConfiguration = (m_CustomConfiguration != null);
}
} catch (Exception e) {
// Error logging & re-throw
}
}
return m_CustomConfiguration;
}
}
When I step through the debugger in code that calls either of the above properties like this:
if (!Program.WCFCache.HasCustomConfiguration)
return new List<CustomComponents>();
...it throws the following exception:
System.AccessViolationException was unhandled
Message="Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Source="System.Windows.Forms"
...
When I step onto the line containing the reference, there is a long pause, followed by a VS popup with the exception.
The exception doesn't appear when I just put a breakpoint after the above code has executed. It doesn't even appear when I put a breakpoint inside the accessors of the properties. It only occurs when I step onto a line with one of those properties from the outside. (So there is a workaround, but it can be a pain.)
Why is this happening? Can I stop it?
Edit: The whole application was written in the last year in 3.5 C#/.NET with WCF communicating between components; meaning, we don't have legacy unmanaged DLLs. Just two unmanaged calls: one to advapi32.dll when the WinForms app is loading, in the username detection procedure. The issue I'm having happens only in this one place in the code, in a place that is about as unrelated to the login section as you can get. The other is to kernel32.dll, in a GC force-flush long after anything is done with the results from calls like the one above.
Are you using any P/Invoke or other such native code? Odds are, that's where you should start looking.
This exception is a symptom of a larger problem, namely memory corruption (that what the exception says, after all). If this was a native application, you'd get a crash.
So, look at any native calls, make sure they're operating correctly, maybe run them under a debugger to try and trap the error closer to home.
Sorry, can't really give better advice given the circumstances.
I eventually found that others have encountered this situation and that it is likely a Visual Studio bug. I was using VS 2008 when the problem occurred.