Can I override _matherr in an C++/CLI dll? - c++-cli

I have an unmanaged c++ application that provides a custom _matherr handler. When this application loads and runs code in unmanaged DLLs, if there is a Math error ( e.g. asin( 100.0 ) ) the custom _matherr function is called and everything works.
However, I'm now trying to create a NUnit Test DLL in C++/CLI that loads the same unmanaged DLL and runs the same code as the application above. What I want to do is add the _matherr function to the C++/CLI dll such that when math errors occur I can perform some custom handler logic.
The C++/CLI dll compiles just fine with the _matherr function defined, but when I force a math error from the unmanaged dll, the _matherr function is not called.
Is this not supported by C++/CLI? The MSDN documentation seems to say _matherr is supported by all C Run times, (with a link to a list of runtimes including the /clr runtime. )

My experience is that defining _matherr does not work if done in a dll. It must be defined in the executable.
I've even seen compilers that when you try to add _matherr in a dll, will not link it in because they don't see anybody making a reference to it.

Maybe you need something like a proxy dll, passing through each function call to the original dll excepting those you want to be handled extra.

Related

Including headers from an unmanaged C++ code inside C++/CLI code

I'm writing a CLR wrapper for an unmanaged C++ library.
There are two files I'm including from the unmanaged lib:
//MyCLIWrapper.h
#include "C:\PATH\TO\UNMANAGED\Header.h"
#include "C:\PATH\TO\UNMANAGED\Body.cpp"
Then I'm writing CLI implementations for the unmanaged library functions:
//MyCLIWrapper.h
// includes ...
void MyCLIWrapper::ManagedFunction()
{
UnmanagedFunction(); // this function is called successfuly
}
However, if my Unmanaged function contains calls to other functions that are defined in other unmanaged header files. This causes a compiler linkage error.
If I add includes to the unmanaged headers that define these functions, my errors get resolved. However, there is a lot of functions, and a lot of includes required.
Is there a different way to approach this?
EDIT:
P.S.
My managed code is in a separate Visual Studio project (output - DLL), and the compile settings are set to /CLR. Unmanaged code is in a separate Win32 project (output - DLL).
Also, after more research I concluded that theoretically I could set my Win32 unmanaged project to CLR and just add my managed classes and headers in there as an entry point, and then it would all compile into a single DLL file. That would probably solve (?) the linkage errors. However, I would prefer to preserve the loose coupling as well as the additional series of problems that can raise from setting my unmanaged project to CLR.
EDIT #2:
The unmanaged class that I'm referencing (body.cpp, header.h) contains includes to the required files that define the functions that are causing the problems. However, my managed code doesn't pick up on the includes that are in the unmanaged body.cpp and header.h.
Linker errors are a different kettle of fish from compiler errors. You forgot to document the exact linker errors you see, but a very common mishap when you compile code with /clr in effect is that the default calling convention for non-C++ member function changes. The default is __clrcall, a convention that's optimized for managed code. While functions compiled without /clr defaults to __cdecl. Which changes the way the function name is mangled. You see this back in the linker error message, is shows that it is looking for a __clrcall function and can't find it.
You'll need to either explicitly declare your functions in the .h file with __cdecl. Or tell the compiler that these functions are not managed code. Which is the best way to tackle it:
#pragma managed(push, off)
#include "unmanagedHeader.h"
#pragma managed(pop)
Solution was fairly simple:
I added both unmanaged and managed projects to a single solution in Visual Studio.
Set the unmanaged project's "Configuration Type" to "Static Library" (.lib).
Right click on the managed project -> References -> Add Reference -> Projects -> -> Add Reference.
Then in my managed class, I include the header.h (only) just like I did in my question.
Compiled successfully!
Thank you

Calling c# code from managed c++ crashes

I have an unmanaged c++ DLL that calls c# code through a managed c++ wrapper. The unmanaged c++ DLL is a plug-in for some application (outside my control). When this application calls the unmanaged c++ DLL everything works fine until the managed c++ code tries to use the c# code. Then it crashes.
I have written a test application that does the same thing as the application, that is, it calls the unmanaged c++ DLL. This works fine.
The code is as simple as it could be:
unmanaged c++:
extern "C" __declspec(dllexport) void UnmanagedMethodCalledUponByApplication()
{
new Bridge();
}
managed c++:
Bridge::Brigde()
{
gcnew Managed(); // This line crashes
}
c#:
public class Managed
{
}
I have tried to add a try-catch (...) block around the problematic line but it doesn't catch the error.
If I replace the gcnew Managed(); line with MessageBox::Show("Alive!"); it works fine. So my guess is that something is wrong with my c# project settings.
I have tried to compile it with different platforms (Any CPU and x86). I have tried to change target framework. I have tried to call a static method in Managed instead of using gcnew. Still crashing.
Any ideas what might be the problem?
Update:
After advise in comments and answer, I attached the debugger. Now I see that I get a System.IO.FileNotFoundException saying that the managed DLL (or one of its dependencies) can't be found.
Here's a guess: The DLLs are placed together, but they are not located in the current directory. The unmanaged c++ DLL is loaded correctly since the main application specifies the path to it. The managed c++ is actually a lib, so that code works fine as well. But when the managed c++ tries to load the c# DLL it looks for it in the wrong directory.
Update:
The way to fix this is to load the c# DLL dynamically, using reflection.
extern "C" __declspec(dllexport)
Yes, that's a cheap and easy way to get the compiler to generate the required stub that loads and initializes the CLR so it can execute managed code. Problem is, it doesn't do anything reasonable to deal with exceptions thrown by managed code. And managed code likes throwing exceptions, they are a terrific trouble-shooting tool. That stops being terrific when there's no way for you to retrieve the exception information.
The best you could possibly do from native code is use the __try/__except keywords to catch the managed exception. Exception code is 0xe0434f4d. But that still doesn't give you access to the information you need, the exception message and the holy stack trace.
You can debug it. Project + Properties, Debugging, change the Debugger Type to "Mixed". Then Debug + Exceptions, tick the Thrown checkbox for CLR Exceptions. The debugger stops when the exception is thrown so you can see what's wrong.
Getting decent diagnostics after you shipped your code requires a better interop mechanism. Like using COM interop or hosting the CLR yourself.

Problems calling a DLL from .NET

I have a VB6 DLL that wraps a call to a 3rd party component. When I call my DLL from VB6, everything works fine, but when I call it from vb.net (2.0 framework targeted - VS2010) I get this error:
AccessViolationException occurred
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
This error only occurs on Windows 7 (Windows XP clients work fine).
I've looked this up and all the articles I found talked about the declaration not being correct. I am not declaring any APIs calls though, the 3rd party component is early bound in my VB6 DLL. I can run the DLL, set a breakpoint, and it goes into my VB6 function, but errors calling a function in the 3rd party component.
My VB6 DLL takes 3 string and one 32bit numeric (long in VB6) parameters. The 3rd party's DLL function that I am calling is taking a string (bstrDNSID as string is what Intellisense shows in VB6). This is where it errors.
Does anyone know how this might be resolved?
Update:
None of the marshalling has helped, so I tried creating a test sub in my VB6 DLL. I hardcoded all the values within the DLL's test sub. It works fine when called from VB6, but gives the same error as above when running from .NET. Also of interest, when I have the VB6 DLL running from the VB6 IDE, I do not get the error when calling the DLL from .NET.
This doesn't really answer your question, but I couldn't fit these examples in the comments.
When marshaling strings to unmanaged DLL calls from .NET, I would receive an AccessViolationException on occasion because I wasn't specifying the right charset. I fixed it by explicitly converting an IntPtr to a string in the charset I needed.
[DllImport("MyDLL.dll", CharSet = CharSet.Ansi)]
static extern void do_something(IntPtr str);
void DoSomethingWrapper(string str) {
var ptr = Marshal.StringToHGlobalAnsi(str);
do_something(ptr);
}
You might need Marshal.StringToBSTR. I don't know if you can call the VB6 function with a pointer or if you'll have to create the pointer in the VB6 DLL.
Here's a question you might find useful: How can I get the charset VB6 is using?
Workaround:
I have found one solution that works. I simply created an ActiveX EXE in VB6 that called the 3rd party component. Works like a charm from .NET.
Also of note, I'd never created an ActiveX EXE and didn't know that regsvr32 will not work to register it. Here is the proper way to register ActiveX EXEs.
VB6 probably declares integer as 16 bit. This is a problem with calling DLLs from VBA too. The solution should be to change your integer to long

Wrapper to unmanaged code

How would you build a wrapper to unmanaged code in order to use it in managed code, and when exactly do you have to do that?
You don't often need a wrapper, many DLLs with straight-forward exported C functions can be pinvoked with the [DllImport] attribute. An exception for C exports would be a poorly designed DLL that requires the client code to release memory, that can't be done by the managed code since it doesn't have access to the allocator.
The case where you have to have a wrapper is a native C++ class. Managed code cannot pinvoke it directly since it doesn't know how to create an instance of the class (which requires knowing the size of the object and calling the constructor) nor how to destroy it (which requires calling the destructor). It is pretty easy to do in C++/CLI. Very mechanical, the SWIG project can do it automatically. Learning that tool is however more of an investment than learning how to write the wrapper.

How to force the unmanaged to managed calls to use the default appdomain?

I have been trying to fix this issue for quite sometime now. I have a C# user control wrapping an activex control (through wrappers created by RCW); This particular activex control loads MFC extension dll which has got C# WPF assembly dependant. This MFC extension dll calls C# WPF assembly through classes compiled as managed (using /clr compiler option).
The problem here is that - when my C# user control gets loaded in C#; It gets into the default app domain and everything seems to be working fine; but whenever a call is made from unmanaged part of MFC extension dll to the managed portion of it, it cramps to find the C# WPF assembly. I googled to find that there seems another appdomain getting created when a call is made from unmanaged portion of MFC extension dll to the managed portion. Right now, I am clueless about this one - How to force the unmanaged to managed calls to use the default appdomain?